Arborescences d'expression

Mise à jour : novembre 2007

Les arborescences d'expression représentent le code de niveau langage sous forme de données. Les données sont stockées dans une structure en forme d'arborescence. Chaque nœud de l'arborescence d'expression représente une expression, par exemple un appel de méthode ou une opération binaire telle que x < y.

L'illustration suivante montre un exemple d'expression et sa représentation sous forme d'arborescence d'expression. Les différentes parties de l'expression sont codées par couleur pour correspondre au nœud d'arborescence d'expression équivalent dans l'arborescence d'expression. Les différents types de nœuds d'arborescence d'expression sont également présentés.

Diagramme de l'arborescence de l'expression

L'exemple de code suivant montre comment l'arborescence d'expression qui représente l'expression lambda num => num < 5 (C#) ou Function(num) num < 5 (Visual Basic) peut être décomposée en 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(ByVal 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

MsgBox(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
*/

Génération d'arborescences d'expression

L'espace de noms System.Linq.Expressions fournit une API pour générer des arborescences d'expression manuellement. La classe Expression contient des méthodes de fabrique statiques qui créent des nœuds d'arborescence d'expression de types spécifiques, par exemple un ParameterExpression, qui représente une expression de paramètre nommée, ou un MethodCallExpression, qui représente un appel de méthode. ParameterExpression, MethodCallExpression et les autres types d'arborescence d'expression spécifiques à l'expression sont également définis dans l'espace de noms System.Linq.Expressions. Ces types dérivent du type abstrait Expression.

Le compilateur peut également générer pour vous une arborescence d'expression. Une arborescence d'expression générée par le compilateur est toujours associée à une racine dans un nœud de type Expression<TDelegate> ; autrement dit, son nœud racine représente une expression lambda.

L'exemple de code suivant montre deux façons de créer une arborescence d'expression qui représente l'expression lambda num => num < 5 (C#) ou Function(num) num < 5 (Visual Basic).

' 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})

' Let the compiler generate the expression tree for
' the lambda expression num => num < 5.
Dim lambda2 As Expression(Of Func(Of Integer, Boolean)) = Function(ByVal num) num < 5

// 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 });

// Let the compiler generate the expression tree for
// the lambda expression num => num < 5.
Expression<Func<int, bool>> lambda2 = num => num < 5;

Immuabilité des arborescences d'expression

Les arborescences d'expression sont immuables. Ainsi, si vous souhaitez modifier une arborescence d'expression, vous devez construire une nouvelle arborescence d'expression en copiant l'arborescence existante et en la modifiant. Vous pouvez utiliser un visiteur de l'arborescence d'expression pour parcourir l'arborescence d'expression existante. Pour plus d'informations, consultez Comment : implémenter un visiteur de l'arborescence de l'expression et Comment : modifier des arborescences d'expression.

Expressions lambda

Lorsqu'une expression lambda est assignée à une variable de type Expression<TDelegate>, le compilateur émet une arborescence d'expression qui représente l'expression lambda. Par exemple, certaines méthodes d'opérateur de requête standard définies dans la classe Queryable ont des paramètres de type Expression<TDelegate>. Lorsque vous appelez ces méthodes, vous pouvez passer une expression lambda et le compilateur générera une arborescence d'expression.

Le type Expression<TDelegate> fournit la méthode Compile qui compile le code représenté par l'arborescence d'expression en un délégué exécutable. Ce code exécutable est équivalent au code exécutable qui aurait été généré si, à l'origine, l'expression lambda avait été assignée à un type délégué.

Remarque :

Seules les arborescences d'expression qui représentent des fonctions, à savoir Expression<TDelegate> et son type parent LambdaExpression, peuvent être compilées en code exécutable. Pour exécuter d'autres types d'arborescences d'expression, vous devez d'abord les encapsuler dans un nœud LambdaExpression. Vous pouvez obtenir ce type de LambdaExpression en appelant la méthode Lambda et en passant l'arborescence d'expression comme argument.

Voir aussi

Tâches

Comment : exécuter des arborescences d'expression

Comment : modifier des arborescences d'expression

Comment : implémenter un visiteur de l'arborescence de l'expression

Concepts

Arborescences d'expression dans LINQ

Expressions lambda

Référence

Expressions lambda (Guide de programmation C#)

System.Linq.Expressions