Partager via


Arborescences d'expression (C# et Visual Basic)

Les arborescences d'expressions représentent du code dans une structure de données arborescente, où chaque nœud est une expression, par exemple un appel de méthode ou une opération binaire comme x < y.

Vous pouvez compiler et exécuter du code représenté par des arborescences d'expressions. Ceci permet la modification dynamique du code exécutable, l'exécution de requêtes LINQ dans différentes bases de données et la création de requêtes dynamiques. Pour plus d'informations sur les arborescences d'expressions dans LINQ, consultez Comment : utiliser des arborescences d'expression pour générer des requêtes dynamiques (C# et Visual Basic).

Les arborescences d'expressions sont également utilisées dans l'environnement d'exécution de langage dynamique (DLR, Dynamic Language Runtime) pour fournir une interopérabilité entre les langages dynamiques et .NET Framework, ainsi que pour permettre aux writers de compilateur d'émettre des arborescences d'expressions au lieu d'utiliser le langage intermédiaire MSIL (Microsoft Intermediate Language). Pour plus d'informations sur le DLR, consultez Vue d'ensemble du Dynamic Language Runtime.

Le compilateur C# ou Visual Basic peut créer pour vous une arborescence d'expressions basée sur une expression lambda anonyme. Vous pouvez aussi créer manuellement des arborescences d'expressions en utilisant l'espace de noms System.Linq.Expressions.

Création d'arborescences d'expressions à partir d'expressions lambda

Quand une expression lambda est affectée à une variable de type Expression, le compilateur produit du code pour générer une arborescence d'expressions qui représente l'expression lambda.

Les compilateurs C# et Visual Basic peuvent générer des arborescences d'expressions seulement à partir d'expressions lambda (ou de lambdas sur une seule ligne). Ils ne peuvent pas analyser des lambdas d'instruction (ou lambdas multilignes). Pour plus d'informations sur les expressions lambda en C#, consultez Expressions lambda (Guide de programmation C#). Pour Visual Basic, consultez Expressions lambda (Visual Basic).

Les exemples de code suivants montrent comment les compilateurs C# et Visual Basic créent une arborescence d'expressions qui représente l'expression 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;

Création d'arborescences d'expressions à l'aide de l'API

Pour créer des arborescences d'expressions à l'aide de l'API, utilisez la classe Expression. Cette classe contient des méthodes de fabrique statiques qui créent des nœuds d'arborescence d'expressions de types spécifiques, par exemple ParameterExpression, qui représente une variable ou un paramètre, ou MethodCallExpression, qui représente un appel de méthode. ParameterExpression, MethodCallExpression et les autres types spécifiques à une expression sont également définis dans l'espace de noms System.Linq.Expressions. Ces types dérivent du type abstrait Expression.

L'exemple de code suivant montre comment créer une arborescence d'expressions qui représente l'expression lambda num => num < 5 (C#) ou Function(num) num < 5 (Visual Basic) à l'aide de 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 });

Dans .NET Framework 4, l'API de l'arborescence d'expressions prend également en charge les affectations et les expressions de flux de contrôle, comme les boucles, les blocs conditionnels et les blocs try-catch. À l'aide de l'API, vous pouvez créer des arborescences d'expressions qui sont plus complexes que celles qui peuvent être créées à partir d'expressions lambda par les compilateurs C# et Visual Basic. L'exemple suivant montre comment créer une arborescence d'expressions qui calcule la factorielle d'un nombre.

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

Pour plus d'informations, consultez Génération de méthodes dynamiques avec des arborescences d'expressions dans Visual Studio 2010.

Analyse des arborescences d'expressions

L'exemple de code suivant montre comment l'arborescence d'expressions qui représente l'expression lambda num => num < 5 (C#) ou Function(num) num < 5 (Visual Basic) peut être décomposée selon ses différentes parties.

        ' 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            

Immuabilité des arborescences d'expressions

Les arborescences d'expressions doivent être immuables. Cela signifie que si vous voulez modifier une arborescence d'expressions, vous devez construire une nouvelle arborescence d'expressions en copiant l'arborescence existante et en y remplaçant les nœuds. Vous pouvez utiliser un visiteur d'arborescence d'expressions pour parcourir l'arborescence d'expressions existante. Pour plus d'informations, consultez Comment : modifier des arborescences d'expression (C# et Visual Basic).

Compilation des arborescences d'expressions

Le type Expression fournit la méthode Compile qui compile le code représenté par une arborescence d'expressions en un délégué exécutable.

L'exemple de code suivant montre comment compiler une arborescence d'expressions et exécuter le code résultant.

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

Pour plus d'informations, consultez Comment : exécuter des arborescences d'expression (C# et Visual Basic).

Voir aussi

Tâches

Comment : exécuter des arborescences d'expression (C# et Visual Basic)

Comment : modifier des arborescences d'expression (C# et Visual Basic)

Référence

Expressions lambda (Guide de programmation C#)

System.Linq.Expressions

Concepts

Vue d'ensemble du Dynamic Language Runtime

Expressions lambda (Visual Basic)

Autres ressources

Concepts de base des arborescences d'expressions

Génération de méthodes dynamiques avec des arborescences d'expressions dans Visual Studio 2010

Concepts de programmation