Compartilhar via


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

Árvores de expressão representam o código em uma estrutura de árvore de dados, 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 código representado por árvores de expressão. Isso permite a modificação de dinâmica de código executável, a execução do LINQ consultas em vários 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: Use as árvores de expressão para criar consultas dinâmicas (C# e Visual Basic) e Demonstra 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 do Microsoft intermediário language (MSIL). Para obter mais informações sobre o DLR, consulte Visão geral de Runtime 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ônima ou criar árvores de expressão manualmente usando o System.Linq.Expressions namespace.

A criação de árvores de expressão 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 de 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 as expressões lambda em C#, consulte Expressões lambda (guia de programação TRANSLATION FROM VPE FOR CSHARP); 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;

Criando á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 criar expressão nós de á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 outros tipos de expressão específicas também estão definidos na System.Linq.Expressions namespace. 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.

Análise de árvores de expressão

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 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ê deseja modificar uma árvore de expressão, você precisa construir uma nova árvore de expressão copiando o já existente e substituindo a nós em ele. 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 as árvores de expressão (C# e Visual Basic).

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

O Expression<TDelegate> tipo fornece a Compile método que compila o código representado por uma árvore de expressão em 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 as árvores de expressão (C# e Visual Basic).

Consulte também

Tarefas

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

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

Referência

Expressões lambda (guia de programação TRANSLATION FROM VPE FOR CSHARP)

System.Linq.Expressions

Conceitos

Visão geral de Runtime de linguagem dinâmica

Expressões Lambda (Visual Basic)

Outros recursos

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

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

Conceitos de programação