Деревья выражений (C#)Expression Trees (C#)

Деревья выражений представляют код в виде древовидной структуры, где каждый узел является выражением, например, вызовом метода или двоичной операцией, такой как x < y.Expression trees represent code in a tree-like data structure, where each node is an expression, for example, a method call or a binary operation such as x < y.

Вы можете компилировать и выполнять код, представленный деревьями выражений.You can compile and run code represented by expression trees. Это позволяет динамически изменять выполняемый код, выполнять запросы LINQ в различных базах данных и создавать динамические запросы.This enables dynamic modification of executable code, the execution of LINQ queries in various databases, and the creation of dynamic queries. См. дополнительные сведения об использовании деревьев выражений в LINQ для создания динамических запросов (C#).For more information about expression trees in LINQ, see How to: Use Expression Trees to Build Dynamic Queries (C#).

Кроме того, деревья выражений используются в среде выполнения динамического языка (DLR) для обеспечения взаимодействия между динамическими языками и платформой .NET Framework, а также и предоставления разработчикам компиляторов возможности выдавать деревья выражений вместо промежуточного языка Microsoft (MSIL).Expression trees are also used in the dynamic language runtime (DLR) to provide interoperability between dynamic languages and the .NET Framework and to enable compiler writers to emit expression trees instead of Microsoft intermediate language (MSIL). Дополнительные сведения о DLR см. в разделе Общие сведения о среде DLR.For more information about the DLR, see Dynamic Language Runtime Overview.

Вы можете использовать компилятор C# или Visual Basic для создания дерева выражений на основе анонимного лямбда-выражения или создания деревьев выражений вручную с помощью пространства имен System.Linq.Expressions.You can have the C# or Visual Basic compiler create an expression tree for you based on an anonymous lambda expression, or you can create expression trees manually by using the System.Linq.Expressions namespace.

Создание деревьев выражений на основе лямбда-выраженийCreating Expression Trees from Lambda Expressions

Когда лямбда-выражение назначается переменной с типом Expression<TDelegate>, компилятор выдает код для создания дерева выражений, представляющего лямбда-выражение.When a lambda expression is assigned to a variable of type Expression<TDelegate>, the compiler emits code to build an expression tree that represents the lambda expression.

Компилятор C# может создавать деревья выражений только на основе лямбда-выражений (или однострочных лямбда-функций).The C# compiler can generate expression trees only from expression lambdas (or single-line lambdas). Они не могут анализировать лямбды операторов (или многострочные лямбды).It cannot parse statement lambdas (or multi-line lambdas). Дополнительные сведения о лямбда-выражениях на C# см. в разделе Лямбда-выражения.For more information about lambda expressions in C#, see Lambda Expressions.

В следующем примере кода демонстрируется способ применения компилятора C# для создания дерева выражений, представляющего лямбда-выражение num => num < 5.The following code examples demonstrate how to have the C# compiler create an expression tree that represents the lambda expression num => num < 5.

Expression<Func<int, bool>> lambda = num => num < 5;  

Создание деревьев выражений с помощью API-интерфейсаCreating Expression Trees by Using the API

Для создания деревьев выражений с помощью API-интерфейса используйте класс Expression.To create expression trees by using the API, use the Expression class. Этот класс содержит статические методы фабрики, позволяющие создать узлы дерева выражения конкретного типа, например, ParameterExpression, который представляет переменную или параметр, или MethodCallExpression, который представляет вызов метода.This class contains static factory methods that create expression tree nodes of specific types, for example, ParameterExpression, which represents a variable or parameter, or MethodCallExpression, which represents a method call. ParameterExpression, MethodCallExpression и другие зависящие от выражения типы также определяются в пространстве имен System.Linq.Expressions.ParameterExpression, MethodCallExpression, and the other expression-specific types are also defined in the System.Linq.Expressions namespace. Эти типы являются производными от абстрактного типа Expression.These types derive from the abstract type Expression.

В следующем примере кода демонстрируется способ создания дерева выражений, представляющего лямбда-выражение num => num < 5, с помощью API.The following code example demonstrates how to create an expression tree that represents the lambda expression num => num < 5 by using the API.

// Add the following using directive to your code file:  
// using System.Linq.Expressions;  
  
// Manually build the expression tree for   
// the lambda expression num => num < 5.  
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");  
ConstantExpression five = Expression.Constant(5, typeof(int));  
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);  
Expression<Func<int, bool>> lambda1 =  
    Expression.Lambda<Func<int, bool>>(  
        numLessThanFive,  
        new ParameterExpression[] { numParam });  

На платформе .NET Framework 4 или более поздней версии API деревьев выражений также поддерживает присваивание и выражения потока управления, такие как циклы, условные блоки и блоки try-catch.In .NET Framework 4 or later, the expression trees API also supports assignments and control flow expressions such as loops, conditional blocks, and try-catch blocks. С помощью API-интерфейса можно создавать деревья выражений, более сложные, чем деревья, создаваемые компилятором C# из лямбда-выражений.By using the API, you can create expression trees that are more complex than those that can be created from lambda expressions by the C# compiler. В следующем примере показан способ создания дерева выражений, которое вычисляет факториал числа.The following example demonstrates how to create an expression tree that calculates the factorial of a number.

// Creating a parameter expression.  
ParameterExpression value = Expression.Parameter(typeof(int), "value");  
  
// Creating an expression to hold a local variable.   
ParameterExpression result = Expression.Parameter(typeof(int), "result");  
  
// Creating a label to jump to from a loop.  
LabelTarget label = Expression.Label(typeof(int));  
  
// Creating a method body.  
BlockExpression block = Expression.Block(  
    // Adding a local variable.  
    new[] { result },  
    // Assigning a constant to a local variable: result = 1  
    Expression.Assign(result, Expression.Constant(1)),  
    // Adding a loop.  
        Expression.Loop(  
    // Adding a conditional block into the loop.  
           Expression.IfThenElse(  
    // Condition: value > 1  
               Expression.GreaterThan(value, Expression.Constant(1)),  
    // If true: result *= value --  
               Expression.MultiplyAssign(result,  
                   Expression.PostDecrementAssign(value)),  
    // If false, exit the loop and go to the label.  
               Expression.Break(label, result)  
           ),  
    // Label to jump to.  
       label  
    )  
);  
  
// Compile and execute an expression tree.  
int factorial = Expression.Lambda<Func<int, int>>(block, value).Compile()(5);  
  
Console.WriteLine(factorial);  
// Prints 120.  

Дополнительные сведения см. в записи блога Generating Dynamic Methods with Expression Trees in Visual Studio 2010 (Создание динамических методов с использованием деревьев выражений в Visual Studio 2010), которая также применима к более поздним версиям Visual Studio.For more information, see Generating Dynamic Methods with Expression Trees in Visual Studio 2010, which also applies to later versions of Visual Studio.

Синтаксический анализ деревьев выраженийParsing Expression Trees

В следующем примере кода показано, как дерево выражений, представляющее лямбда-выражение num => num < 5, может быть разложено на части.The following code example demonstrates how the expression tree that represents the lambda expression num => num < 5 can be decomposed into its parts.

// Add the following using directive to your code file:  
// using System.Linq.Expressions;  
  
// Create an expression tree.  
Expression<Func<int, bool>> exprTree = num => num < 5;  
  
// Decompose the expression tree.  
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];  
BinaryExpression operation = (BinaryExpression)exprTree.Body;  
ParameterExpression left = (ParameterExpression)operation.Left;  
ConstantExpression right = (ConstantExpression)operation.Right;  
  
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",  
                  param.Name, left.Name, operation.NodeType, right.Value);  
  
// This code produces the following output:  
  
// Decomposed expression: num => num LessThan 5  

Неизменность деревьев выраженийImmutability of Expression Trees

Деревья выражений должны быть неизменными.Expression trees should be immutable. Это означает, что если требуется изменить дерево выражений, следует создать новое дерево выражений путем копирования существующего и заменить узлы в нем.This means that if you want to modify an expression tree, you must construct a new expression tree by copying the existing one and replacing nodes in it. Для прохода по существующему дереву выражений можно использовать другое дерево выражений (посетитель).You can use an expression tree visitor to traverse the existing expression tree. Дополнительные сведения см. в разделе Практическое руководство. Изменение деревьев выражений (C#).For more information, see How to: Modify Expression Trees (C#).

Компиляция деревьев выраженийCompiling Expression Trees

Тип Expression<TDelegate> предоставляет метод Compile, который компилирует код, представляемый деревом выражений, в исполняемый делегат.The Expression<TDelegate> type provides the Compile method that compiles the code represented by an expression tree into an executable delegate.

В следующем примере кода показан способ компиляции дерева выражений и выполнения результирующего кода.The following code example demonstrates how to compile an expression tree and run the resulting code.

// Creating an expression tree.  
Expression<Func<int, bool>> expr = num => num < 5;  
  
// Compiling the expression tree into a delegate.  
Func<int, bool> result = expr.Compile();  
  
// Invoking the delegate and writing the result to the console.  
Console.WriteLine(result(4));  
  
// Prints True.  
  
// You can also use simplified syntax  
// to compile and run an expression tree.  
// The following line can replace two previous statements.  
Console.WriteLine(expr.Compile()(4));  
  
// Also prints True.  

Дополнительные сведения см. в разделе Практическое руководство. Выполнение деревьев выражений (C#).For more information, see How to: Execute Expression Trees (C#).

См. такжеSee also