Пытаюсь понять, что такое дерево выражений

#c# #delegates #lambda #expression-trees

#c# #делегирует #лямбда #деревья выражений

Вопрос:

Оба приведенных ниже фрагмента выдают один и тот же результат. Я понимаю, как Func инкапсулирует метод с одним параметром и возвращает значение bool. И вы можете либо назначить ему метод, анонимный метод, либо лямбда-выражение.

 Func<int, bool> deleg = i => i < 5;
Console.WriteLine("deleg(4) = {0}", deleg(4));
  

Ниже используются деревья выражений, которые я еще не до конца понимаю. Почему я должен хотеть сделать это таким образом? Является ли это более гибким, какое преимущество это дает мне?

 System.Linq.Expressions.Expression<Func<int, bool>> expr = i => i < 5;
Func<int, bool> deleg2 = expr.Compile();
Console.WriteLine("deleg2(4) = {0}", deleg2(4));
  

Ответ №1:

По сути, дерево выражений — это тело лямбда-выражения, которое позволяет вам

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

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

Всякий раз, когда вы хотите

  • создавайте выражения динамически (я имею в виду: конструируйте, а не распределяйте)
  • динамически работать с выражениями

Function<> типов недостаточно.

Ответ №2:

Суть деревьев выражений в том, что с ними можно делать больше, чем просто компилировать их в функцию. Вы можете проверять их, изменять и компилировать во что-то другое, кроме функций .net.

Например, Linq2SQL компилирует деревья выражений в код SQL. Вы не смогли бы сделать это с помощью простого .сетевая функция.

Комментарии:

1. как вы их проверяете? как называется этот процесс? примеры?

2. @codecompleting: использование методов и свойств класса Expression и его подклассов . Вы можете увидеть небольшой пример, например, в этой статье .

Ответ №3:

В вашем первом примере вы просто «жестко запрограммировали» тело функции и назначили его делегату.

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

Преимущество заключается в том, что вы можете изменять и проверять эту структуру данных.

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

Ответ №4:

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

С другой стороны, скомпилированная функция — это не что иное, как последовательность кода CIL. Вы все еще можете проверить это программно, но вы проверяете не определение, а скорее — его вывод компилятором.