Árvores de expressão (C# e Visual Basic)

Árvores de expressão representam o código em uma estrutura de dados de árvore, onde cada nó é uma expressão, por exemplo, uma chamada de método ou uma operação binário, como x < y.

Você pode compilar e executar o código representado por árvores de expressão.Isso permite a modificação dinâmica de código executável, a execução do LINQ consultas em diversos bancos de dados e a criação de consultas dinâmicas.Para obter mais informações sobre árvores de expressão em LINQ, consulte Como: usar árvores de expressão para criar consultas dinâmicas (C# e Visual Basic) e Passo a passo: Criando um provedor IQueryable LINQ.

Árvores de expressão também são usados em tempo de execução de linguagem dinâmica (DLR) para fornecer interoperabilidade entre linguagens dinâmicas e o.NET Framework e para permitir que os escritores de compiladores emitir expressão árvores em vez de Microsoft intermediárias language (MSIL).Para obter mais informações sobre o DLR, consulte Visão geral de tempo de execução de linguagem dinâmica.

Você pode fazer com que o compilador C# ou Visual Basic criar uma árvore de expressão para você com base em uma expressão lambda anônimo ou você pode criar árvores de expressão manualmente usando o System.Linq.Expressions espaço para nome.

Criando árvores de expressão de expressões Lambda

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.

C# e Visual Basic compiladores podem gerar árvores de expressão somente de lambdas expressão (ou lambdas de linha única).Ele não é possível analisar lambdas de instrução (ou lambdas várias linhas).Para obter mais informações sobre expressões lambda em C#, consulte Expressões lambda (guia de programação do C#); para Visual Basic, consulte Expressões lambda (Visual Basic).

Os exemplos de código a seguir demonstram como ter C# e compiladores de Visual Basic criar uma árvore de expressão que representa a expressão lambda num => num < 5 (C#) ou Function(num) num < 5 (Visual Basic).

Dim lambda As Expression(Of Func(Of Integer, Boolean)) =
    Function(num) num < 5
Expression<Func<int, bool>> lambda = num => num < 5;

A criação de árvores de expressão usando a API

Para criar árvores de expressão usando a API, use o Expression classe.Essa classe contém métodos estáticos de fábrica que crie expressão nós da árvore de tipos específicos, por exemplo, ParameterExpression, que representa uma variável ou parâmetro, ou MethodCallExpression, que representa uma chamada de método.ParameterExpression, MethodCallExpression, e os outros tipos de expressão específicas também estão definidos na System.Linq.Expressions espaço para nome.Esses tipos derivam do tipo abstrato 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 (C#) ou Function(num) num < 5 (Visual Basic) usando a API.


' Import the following namespace to your project: System.Linq.Expressions

' Manually build the expression tree for the lambda expression num => num < 5.
Dim numParam As ParameterExpression = Expression.Parameter(GetType(Integer), "num")
Dim five As ConstantExpression = Expression.Constant(5, GetType(Integer))
Dim numLessThanFive As BinaryExpression = Expression.LessThan(numParam, five)
Dim lambda1 As Expression(Of Func(Of Integer, Boolean)) =
  Expression.Lambda(Of Func(Of Integer, Boolean))(
        numLessThanFive,
        New ParameterExpression() {numParam})

            // 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, a API de árvores de expressão também suporta as atribuições e expressões de fluxo de controle, como loops, blocos condicionais, e try-catch blocos.Usando a API, você pode criar árvores de expressão são mais complexos do que aqueles que podem ser criados a partir de expressões lambda pelos compiladores C# e Visual Basic.O exemplo a seguir demonstra como criar uma árvore de expressão que calcula o fatorial de um número.

' Creating a parameter expression.
Dim value As ParameterExpression =
    Expression.Parameter(GetType(Integer), "value")

' Creating an expression to hold a local variable. 
Dim result As ParameterExpression =
    Expression.Parameter(GetType(Integer), "result")

' Creating a label to jump to from a loop.
Dim label As LabelTarget = Expression.Label(GetType(Integer))

' Creating a method body.
Dim block As BlockExpression = Expression.Block(
    New ParameterExpression() {result},
    Expression.Assign(result, Expression.Constant(1)),
    Expression.Loop(
        Expression.IfThenElse(
            Expression.GreaterThan(value, Expression.Constant(1)),
            Expression.MultiplyAssign(result,
                Expression.PostDecrementAssign(value)),
            Expression.Break(label, result)
        ),
        label
    )
)

' Compile an expression tree and return a delegate.
Dim factorial As Integer =
    Expression.Lambda(Of Func(Of Integer, Integer))(block, value).Compile()(5)

Console.WriteLine(factorial)
' Prints 120.
// 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 obter mais informações, consulte Gerar métodos dinâmicos com árvores de expressão em 2010 de Visual Studio.

Árvores de expressão de análise.

O exemplo de código a seguir demonstra como a expressão árvore que representa a expressão lambda num => num < 5 (C#) ou Function(num) num < 5 (Visual Basic) podem ser decomposto em suas partes.


        ' Import the following namespace to your project: System.Linq.Expressions

        ' Create an expression tree.
        Dim exprTree As Expression(Of Func(Of Integer, Boolean)) = Function(num) num < 5

        ' Decompose the expression tree.
        Dim param As ParameterExpression = exprTree.Parameters(0)
        Dim operation As BinaryExpression = exprTree.Body
        Dim left As ParameterExpression = operation.Left
        Dim right As ConstantExpression = operation.Right

        Console.WriteLine(String.Format("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


// 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ão

Árvores de expressão devem ser imutáveis.Isso significa que, se você quiser modificar uma árvore de expressão, você precisa construir uma nova árvore de expressão copiando o já existente e substituindo nós nele.Você pode usar um visitante da árvore de expressão para percorrer a árvore de expressão existente.Para obter mais informações, consulte Como: modificar árvores de expressão (C# e Visual Basic).

Árvores de expressão de compilação.

O Expression<TDelegate> tipo fornece a Compile método compila o código representado por uma árvore de expressão para um delegado executável.

O exemplo de código a seguir demonstra como compilar uma árvore de expressões e executar o código resultante.

' Creating an expression tree.
Dim expr As Expression(Of Func(Of Integer, Boolean)) =
    Function(num) num < 5

' Compiling the expression tree into a delegate.
Dim result As Func(Of Integer, Boolean) = 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.
// 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, consulte Como: executar árvores de expressão (C# e Visual Basic).

Consulte também

Tarefas

Como: executar árvores de expressão (C# e Visual Basic)

Como: modificar árvores de expressão (C# e Visual Basic)

Referência

Expressões lambda (guia de programação do C#)

System.Linq.Expressions

Conceitos

Visão geral de tempo de execução de linguagem dinâmica

Expressões lambda (Visual Basic)

Outros recursos

Noções básicas da árvore de expressão

gerar métodos dinâmicos com árvores de expressão em 2010 de Visual Studio

Conceitos de programação