Condividi tramite


Strutture ad albero dell'espressione (C# e Visual Basic)

Le strutture ad albero dell'espressione rappresentano il codice in una struttura di dati ad albero, in cui ogni nodo è un'espressione, ad esempio una chiamata al metodo o un'operazione binaria quale x < y.

È possibile compilare ed eseguire il codice rappresentato dalle strutture ad albero dell'espressione.In questo modo, è possibile modificare in modo dinamico il codice eseguibile, eseguire query LINQ in vari database e creare query dinamiche.Per ulteriori informazioni sulle strutture ad albero dell'espressione in LINQ, vedere Procedura: utilizzare strutture ad albero dell'espressione per la compilazione di query dinamiche (C# e Visual Basic) e Procedura dettagliata: creazione di un provider LINQ IQueryable.

Le strutture ad albero dell'espressione vengono utilizzate anche in DLR per offrire l'interoperabilità tra linguaggi dinamici e .NET Framework e consentire la generazione di tali strutture da parte dei writer di compilatori anziché di Microsoft Intermediate Language (MSIL).Per ulteriori informazioni su DLR, vedere Cenni preliminari su Dynamic Language Runtime.

È possibile creare una struttura ad albero dell'espressione automaticamente mediante il compilatore C# o Visual Basic in base a un'espressione lambda anonima o creare tali strutture manualmente tramite lo spazio dei nomi System.Linq.Expressions.

Creazione di strutture ad albero dell'espressione da espressioni lambda

Quando un'espressione lambda viene assegnata a una variabile di tipo Expression<TDelegate>, il compilatore genera codice per compilare una struttura ad albero dell'espressione che rappresenta l'espressione lambda.

I compilatori C# e Visual Basic possono generare strutture ad albero dell'espressione solo da espressioni lambda (o lambda a riga singola).Non è possibile analizzare lambda di istruzioni (o lambda a più righe).Per ulteriori informazioni sulle espressioni lambda in C#, vedere Espressioni lambda (Guida per programmatori C#); per Visual Basic, vedere Espressioni lambda (Visual Basic).

Negli esempi di codice seguenti viene illustrato come creare una struttura ad albero dell'espressione che rappresenta l'espressione lambda num => num < 5 (C#) o Function(num) num < 5 (Visual Basic) utilizzando i compilatori C# e Visual Basic.

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

Creazione di strutture ad albero dell'espressione tramite l'API

Per creare strutture ad albero dell'espressione tramite l'API, utilizzare la classe Expression.Questa classe contiene metodi factory statici che creano nodi della struttura ad albero dell'espressione di tipi specifici, ad esempio ParameterExpression, che rappresenta una variabile o un parametro, o MethodCallExpression, che rappresenta una chiamata al metodo.ParameterExpression, MethodCallExpression e gli altri tipi specifici dell'espressione vengono inoltre definiti nello spazio dei nomi System.Linq.Expressions.Tali tipi derivano dal tipo astratto Expression.

Nell'esempio di codice seguente viene illustrato come creare una struttura ad albero dell'espressione che rappresenta l'espressione lambda num => num < 5 (C#) o Function(num) num < 5 (Visual Basic) tramite l'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 });

In .NET Framework 4, l'API delle strutture ad albero dell'espressione supporta inoltre assegnazioni ed espressioni del flusso di controllo, quali cicli, blocchi condizionali e blocchi try-catch.Tramite l'API, è possibile creare strutture ad albero dell'espressione più complesse rispetto a quelle create dalle espressioni lambda mediante i compilatori C# e Visual Basic.Nell'esempio seguente viene illustrato come creare una struttura ad albero dell'espressione che calcola il fattoriale di un numero.

' 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.

Per ulteriori informazioni, vedere l'articolo relativo alla generazione di metodi dinamici con strutture ad albero dell'espressione in Visual Studio 2010 (la pagina potrebbe essere in inglese).

Analisi delle strutture ad albero dell'espressione

Nell'esempio di codice seguente viene illustrato come la struttura ad albero dell'espressione che rappresenta l'espressione lambda num => num < 5 (C#) o Function(num) num < 5 (Visual Basic) possa essere scomposta nelle relative parti.


        ' 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            

Immutabilità delle strutture ad albero dell'espressione

Le strutture ad albero dell'espressione devono essere immutabili.Ciò significa che se si desidera modificare una struttura ad albero dell'espressione, è necessario costruirne una nuova copiando quella esistente e sostituendone i nodi.Per attraversare la struttura ad albero dell'espressione esistente, è possibile utilizzare un visitatore della struttura a albero dell'espressione.Per ulteriori informazioni, vedere Procedura: modificare strutture ad albero dell'espressione (C# e Visual Basic).

Compilazione di strutture ad albero dell'espressione

Il tipo Expression<TDelegate> fornisce il metodo Compile che compila il codice rappresentato da una struttura ad albero dell'espressione in un delegato eseguibile.

Nell'esempio di codice seguente viene illustrato come compilare una struttura ad albero dell'espressione ed eseguire il codice risultante.

' 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.

Per ulteriori informazioni, vedere Procedura: eseguire alberi delle espressioni (C# e Visual Basic).

Vedere anche

Attività

Procedura: eseguire alberi delle espressioni (C# e Visual Basic)

Procedura: modificare strutture ad albero dell'espressione (C# e Visual Basic)

Riferimenti

Espressioni lambda (Guida per programmatori C#)

System.Linq.Expressions

Concetti

Cenni preliminari su Dynamic Language Runtime

Espressioni lambda (Visual Basic)

Altre risorse

Nozioni fondamentali sulle strutture ad albero dell'espressione

Generazione di metodi dinamici con le strutture ad albero dell'espressione in Visual Studio 2010

Nozioni di base sulla programmazione