Деревья выражений .net

Я хотел бы получить хорошее представление о предмете, поэтому хочу задать следующие вопросы сообществу:

  1. Какие преимущества приносят деревья выражений?
  2. Что именно означает это утверждение: «Деревья выражений — это данные, скомпилированные в виде кода»?
  3. Какие общие проблемы решают деревья выражений и функциональное программирование в контексте .net?
  4. Какие есть хорошие онлайн-ресурсы, чтобы набрать скорость в сабже?

person dexter    schedule 10.11.2010    source источник


Ответы (2)


  1. Они дают возможность брать ваш исходный код и «понимать» его во время выполнения — провайдеры LINQ являются главной целью этого

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

  3. Честно говоря, деревья выражений и функциональное программирование кажутся мне несколько ортогональными. Оба часто имеют дело с функциями более высокого порядка, но это все.

  4. возможно, MSDN?

person Jon Skeet    schedule 10.11.2010
comment
Использует ли Linq деревья выражений для всех реализаций? Linq-to-SQL? Объекты Linq2? Linq2Xml? Означает ли это также, что если вы создадите свой собственный провайдер Linq (внедрите IQuaryable‹T› и IQueryProvider), вам потребуется реализация деревьев выражений, и если да, то почему и как (конечно, на высоком уровне)? - person dexter; 10.11.2010
comment
@Max: Нет, только некоторые реализации используют деревья выражений. Например, для LINQ to Objects лямбда-выражения просто компилируются в делегаты. (LINQ to XML на самом деле не является поставщиком LINQ — это XML API, который просто хорошо работает с LINQ to Objects.) - person Jon Skeet; 10.11.2010
comment
Если вы создадите свой собственный поставщик LINQ, реализующий IQueryable, вам будут представлены деревья выражений, представляющие запросы — затем вам нужно изучить эти деревья выражений и преобразовать их в соответствующий формат. - person Jon Skeet; 10.11.2010

Какие преимущества приносят деревья выражений?

Деревья выражений позволяют программе упрощенно манипулировать частью своей реализации во время выполнения. Они позволяют передавать выражения как представление их структуры, а не просто делегат, который можно вызывать.

Что именно означает это утверждение: «Деревья выражений — это данные, скомпилированные в виде кода»?

Языки до C#/.NET поддерживали такого рода манипуляции... лучшим примером является LISP. Способность представлять структуру программы в структуре данных внутри программы называется гомоиконичностью. . C# поддерживает ограниченную гомоиконичность в виде деревьев выражений. Язык C# позволяет прозрачно создавать деревья выражений из (подмножества) выражений в вашем коде. Например:

int x = 3;
Expression<Func<bool>> IsXLessThan4Expr = () => x < 4;

Func<bool> IsXLessThan4 = () => x < 4;

Переменная IsXLessThan4Expr берется из лямбда-выражения в виде дерева выражений. Теперь мы можем просмотреть представление этого выражения, если хотим понять, какова его структура, и манипулировать им, если захотим. Делегат IsXLessThan4, напротив, не может быть проинспектирован... его можно только вызывать. Конечно, вы всегда можете получить необработанный IL для любого метода (при условии, что у вас есть необходимые разрешения), но гораздо сложнее изменить логическую структуру программы из IL, чем из дерева выражений.

Какие общие проблемы решают деревья выражений и функциональное программирование в контексте .net?

Лучшим примером использования деревьев выражений для решения нетривиальной задачи является LINQ-to-SQL, где реализация IQueryable способна преобразовывать деревья выражений запросов, написанные на C#, в эквивалентные запросы SQL, которые могут выполняться базой данных. .

Деревья выражений также позволяют генерировать код C# на лету, поскольку деревья выражений могут быть скомпилированы в лямбда-выражения. Вот пример этого:

var paramNotification = 
      Expression.Parameter(typeof (NotificationEntry), "noti");

Func<NotificationEntry, bool> predicate = 
        m_PredicateExpr = Expression.Lambda<Func<NotificationEntry, bool>>(
            Expression.LessThan(
                Expression.Property(paramNotification, "Value"),
                Expression.Constant(100)),
            new[] {paramNotification})
        .Compile();

Приведенный выше фрагмент создает выражение, которое сравнивает поле Value объекта NotificationEntry с некоторой предоставленной константой (100) и компилирует его в лямбду, которую мы можем вызвать.

Какие есть хорошие онлайн-ресурсы, чтобы набрать скорость по этому вопросу?

MSDN, вероятно, лучший выбор на данный момент.

person LBushkin    schedule 10.11.2010
comment
Итак, можно ли назвать дерево выражений динамическим фрагментом кода, представляющим логическое выражение для манипулирования некоторыми данными, которые можно применить к структуре во время выполнения? - person dexter; 10.11.2010
comment
@Макс: Не совсем так. Дерево выражений само по себе не является кодом. Это структура данных. Вы можете преобразовать дерево выражений в код, используя Compile(), который вернет соответствующий делегат. - person LBushkin; 10.11.2010
comment
Я думаю, что ваш ответ очень помог мне понять тему. Спасибо! Чего я раньше не знал, так это того, что основное различие между делегатом или лямбдой и выражением заключается в том, что выражение можно анализировать и манипулировать им до того, как код решит его вызвать. Отсюда и реализация класса посетителей во многих реализациях Linq2Whatever Provider, правильно? - person dexter; 10.11.2010
comment
@Max: Да, точно. Существует множество реализаций IQueryable, которые используют возможность проверки и преобразования деревьев выражений, чтобы код C# мог представлять запросы к другим типам ресурсов. Они делают это, посещая представление выражения и преобразовывая его в форму, соответствующую их предметной области. Что действительно приятно, так это то, что в C# лямбда-выражение может быть прозрачно передано любому методу, который принимает параметр типа Expression<...> — это позволяет писать потребляемый код естественным образом, не беспокоясь о базовых деталях преобразования. - person LBushkin; 10.11.2010
comment
отлично, это имеет смысл, поэтому я думаю, что мне следует написать свой собственный поставщик Linq, чтобы лучше понять механику. - person dexter; 10.11.2010