Подтвердить что ты не робот

Ошибка в С#: "дерево выражений не может содержать базовый доступ" - почему бы и нет?

Я вызывал метод, который принимает Expression<Func<bool>>.

Как часть выражения, которое я передавал:

this.Bottom == base.lineView.Top

Компилятор дал мне ошибку, что

дерево выражений не может содержать базовый доступ

Поэтому я просто изменил его на

this.Bottom == this.lineView.Top

потому что элемент был защищен в любом случае, и теперь он работает.

Но эта ошибка действительно вызвала меня: почему это проблема base была проблемой? Особенно, если использование this вместо этого будет работать, но синтаксически будет тем же результатом (к той же переменной обращаются)?

4b9b3361

Ответ 1

В документации System.Linq.Expressions.Expression я не думаю, что существует тип выражения, который представляет "доступ к базовому члену". Не забывайте, что, хотя в вашем случае это означало то же самое, что только this, в других случаях это не было бы:

class Test
{
    void Foo()
    {
        Expression<Func<string>> baseString = () => base.ToString();
    }

    public override string ToString()
    {
        return "overridden value";
    }
}

Здесь это будет представлять не виртуальный вызов Object.ToString() (для this). Я не вижу, как это будет представлено в дереве выражений, следовательно, ошибка.

Теперь это приводит к очевидному вопросу о том, почему нет представления о вызове не виртуального базового элемента в деревьях выражений - боюсь, я не могу ответить на эту часть... хотя я вижу, что если вы можете создать это выражение программно, что позволит вам обойти обычный полиморфизм извне, а не только внутри самого класса (что является нормальным случаем). Это может быть причиной. (По общему признанию, существуют другие способы вызова методов не виртуально, но это другой вопрос, и я смею утверждать, что существуют ситуации, когда деревья выражений "доверены", но другого кода нет.)

Ответ 2

Ответ Джона правильный. Я хочу следить за комментарием Джона:

Я вижу, что если бы вы могли программно создать это выражение, это позволило бы обойти нормальный полиморфизм извне, а не только внутри самого класса (что является нормальным случаем). Это может быть причиной

Предположим, что у вас есть

public abstract class B // Prevent instantiation
{
    internal B() {} // Prevent subclassing outside the assembly. 
    public virtual void Dangerous() { ... } 
}
public sealed class D : B 
{ 
  public override void Dangerous() 
  { 
    if (!Allowed()) throw whatever;
    base.Dangerous();
  }

Нельзя использовать частично доверенный код с D для вызова B.Dangerous в экземпляре D без проверки безопасности в D.Dangerous.

Таким образом, верификатор CLR запрещает вам выполнять не виртуальный вызов (базовый вызов, конечно, не виртуальный) по виртуальному методу извне иерархии классов. На самом деле, он идет еще дальше; вы даже не можете выполнить это из класса, вложенного в D! (Конечно, если вашей программе предоставляется право пропустить проверку, то вы можете делать все, что хотите, вы можете разыменовывать произвольные указатели на память в непроверяемом коде, что намного хуже, чем статический вызов виртуального метода.)

Когда мы разрабатывали деревья выражений, мы не хотели иметь дело с этой грязной проблемой безопасности. Проще всего было просто сделать все незаконным.

Возникло множество других проблем безопасности с деревьями выражений, которые не могли быть легко решены, но это тема для другого дня.