Что такое дерево выражений (Expression Tree) в C#?

«Что такое дерево выражений (Expression Tree) в C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Дерево выражений (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);

Практическое применение:

  1. LINQ to SQL/Entity Framework: Когда вы пишете db.Users.Where(u => u.Age > 18), выражение u => u.Age > 18 передаётся как Expression<Func<User, bool>>. Поставщик EF анализирует это дерево и преобразует его в SQL WHERE Age > 18, а не выполняет фильтрацию в памяти.
  2. Динамическая генерация кода: Создание специализированных методов на лету для оптимизации.
  3. Валидация и анализ кода: Проверка структуры выражений перед выполнением.