Árvores de expressão (C#)Expression Trees (C#)

Árvores de expressão representam código em uma estrutura de dados de árvore, onde cada nó é, por exemplo, uma expressão, uma chamada de método ou uma operação binária como 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.

Você pode compilar e executar código representado por árvores de expressão.You can compile and run code represented by expression trees. Isso permite a modificação dinâmica de código executável, a execução de consultas LINQ em vários bancos de dados e a criação de consultas dinâmicas.This enables dynamic modification of executable code, the execution of LINQ queries in various databases, and the creation of dynamic queries. Confira mais informações sobre árvores de expressão no LINQ em Como: usar árvores de expressão para compilar consultas dinâmicas (C#).For more information about expression trees in LINQ, see How to: Use Expression Trees to Build Dynamic Queries (C#).

Árvores de expressão também são usadas no tempo de execução de linguagem dinâmica (DLR) para fornecer interoperabilidade entre linguagens dinâmicas e o .NET Framework e permitir que gravadores compiladores emitam árvores de expressão em vez de Microsoft intermediate language (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). Para obter mais informações sobre o DLR, consulte Visão geral do Dynamic Language Runtime.For more information about the DLR, see Dynamic Language Runtime Overview.

Você pode fazer o compilador C# ou do Visual Basic criar uma árvore de expressões para você com base em uma expressão lambda anônima ou criar árvores de expressão manualmente usando o namespace 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.

Criando árvores de expressão de expressões LambdaCreating Expression Trees from Lambda Expressions

Quando uma expressão lambda é atribuída a uma variável do tipo Expression<TDelegate>, o compilador emite código para criar uma árvore de expressão que representa a expressão lambda.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.

Os compiladores do C# podem gerar árvores de expressão apenas por meio de expressões lambda (ou lambdas de linha única).The C# compiler can generate expression trees only from expression lambdas (or single-line lambdas). Ele não é possível analisar instruções lambdas (ou lambdas de várias linhas).It cannot parse statement lambdas (or multi-line lambdas). Para obter mais informações sobre expressões lambda no C#, consulte Expressões lambda.For more information about lambda expressions in C#, see Lambda Expressions.

Os exemplos de código a seguir demonstram como fazer os compiladores do C# criarem uma árvore de expressão que representa a expressão lambda 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;  

Criando árvores de expressão usando a APICreating Expression Trees by Using the API

Para criar árvores de expressão usando a API, use a classe Expression.To create expression trees by using the API, use the Expression class. Essa classe contém métodos de fábrica estáticos para criar nós de árvore de expressão de tipos específicos, por exemplo, ParameterExpression, que representa uma variável ou parâmetro, ou MethodCallExpression, que representa uma chamada de método.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 e os outros tipos específicos de expressão também são definidos no namespace System.Linq.Expressions.ParameterExpression, MethodCallExpression, and the other expression-specific types are also defined in the System.Linq.Expressions namespace. Esses tipos derivam do tipo abstrato Expression.These types derive from the abstract type Expression.

O exemplo de código a seguir demonstra como criar uma árvore de expressão que representa a expressão lambda num => num < 5 usando a 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 });  

No .NET Framework 4 ou posterior, a API de árvores de expressão também dá suporte a atribuições e expressões de fluxo de controle, como loops, blocos condicionais e blocos 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. Usando a API, você pode criar árvores de expressão mais complexas do que aquelas que podem ser criadas por meio de expressões lambda pelos compiladores do 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. O exemplo a seguir demonstra como criar uma árvore de expressão que calcula o fatorial de um número.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.  

Para saber mais, confira Gerar métodos dinâmicos com árvores de expressão no Visual Studio 2010, que também se aplica a versões mais recentes do 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.

Analisando árvores de expressãoParsing Expression Trees

O exemplo de código a seguir demonstra como a árvore de expressão que representa a expressão lambda num => num < 5 pode ser decomposta em suas partes.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  

Imutabilidade das árvores de expressãoImmutability of Expression Trees

Árvores de expressão devem ser imutáveis.Expression trees should be immutable. Isso significa que se você deseja modificar uma árvore de expressão, deverá criar uma nova árvore de expressão, copiando a existente e substituindo seus nós.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. Você pode usar um visitantes de árvore expressão para percorrer a árvore de expressão existente.You can use an expression tree visitor to traverse the existing expression tree. Para obter mais informações, confira Como: modificar árvores de expressão (C#).For more information, see How to: Modify Expression Trees (C#).

Compilando árvores de expressãoCompiling Expression Trees

O tipo Expression<TDelegate> fornece o método Compile que compila o código representado por uma árvore de expressão para um delegado executável.The Expression<TDelegate> type provides the Compile method that compiles the code represented by an expression tree into an executable delegate.

O exemplo de código a seguir demonstra como compilar uma árvore de expressão e executar o código resultante.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.  

Para obter mais informações, confira Como: executar árvores de expressão (C#).For more information, see How to: Execute Expression Trees (C#).

Consulte tambémSee also