Ответ
Дерево выражений (Expression Tree) — это древовидная структура данных, которая представляет код на этапе выполнения в виде данных, а не исполняемых инструкций. Это позволяет анализировать, модифицировать или транслировать код (например, в SQL-запрос) перед его выполнением.
Основное отличие от делегата:
- Делегат
Func<int, int>:x => x + 1— это скомпилированный код для немедленного выполнения. - Выражение
Expression<Func<int, int>>:x => x + 1— это данные, описывающие структуру этого лямбда-выражения (узел сложения с параметромxи константой1).
Пример создания и компиляции дерева выражений "вручную":
using System.Linq.Expressions;
// Цель: создать выражение, эквивалентное (x) => x * x + 2
// 1. Параметр выражения.
ParameterExpression paramX = Expression.Parameter(typeof(int), "x");
// 2. Константа '2'.
ConstantExpression constantTwo = Expression.Constant(2, typeof(int));
// 3. Умножение: x * x.
BinaryExpression multiply = Expression.Multiply(paramX, paramX);
// 4. Сложение: (x * x) + 2.
BinaryExpression addBody = Expression.Add(multiply, constantTwo);
// 5. Построение лямбда-выражения.
Expression<Func<int, int>> lambdaExpression =
Expression.Lambda<Func<int, int>>(addBody, paramX);
// 6. Дерево выражений можно проанализировать.
Console.WriteLine(lambdaExpression.Body); // Выведет: ((x * x) + 2)
// 7. Компиляция дерева в исполняемый делегат.
Func<int, int> compiledDelegate = lambdaExpression.Compile();
// 8. Вызов.
int result = compiledDelegate(5); // (5 * 5) + 2 = 27
Console.WriteLine(result);
Практическое применение:
- LINQ to SQL/Entity Framework: Когда вы пишете
db.Users.Where(u => u.Age > 18), выражениеu => u.Age > 18передаётся какExpression<Func<User, bool>>. Поставщик EF анализирует это дерево и преобразует его в SQLWHERE Age > 18, а не выполняет фильтрацию в памяти. - Динамическая генерация кода: Создание специализированных методов на лету для оптимизации.
- Валидация и анализ кода: Проверка структуры выражений перед выполнением.