Prise en charge du runtime .NET pour les arborescences d’expression

Il existe une longue liste de classes dans le runtime .NET qui fonctionnent avec des arborescences d’expressions. Vous pouvez voir la liste complète dans System.Linq.Expressions. Au lieu d’énumérer la liste complète, nous allons comprendre comment les classes du runtime ont été conçues.

Dans la conception du langage, une expression est un corps de code qui évalue et retourne une valeur. Les expressions peuvent être simples : l’expression constante 1 retourne la valeur constante 1. Elles peuvent être plus compliquées : l’expression (-B + Math.Sqrt(B*B - 4 * A * C)) / (2 * A) retourne une racine pour une équation quadratique (dans le cas où l’équation a une solution).

System.Linq.Expression et types dérivés

L’une des complexités liées à l’utilisation des arborescences d’expressions est que de nombreuses sortes d’expressions sont valides à de nombreux endroits dans les programmes. Prenez par exemple une expression d’assignation. La partie droite d’une assignation peut être une valeur constante, une variable, une expression d’appel de méthode ou autre. Cette flexibilité linguistique signifie que vous pouvez rencontrer de nombreux types d’expressions différents à n’importe quel endroit dans les nœuds d’une arborescence quand vous parcourez une arborescence d’expressions. Ainsi, quand vous travaillez avec le type d’expression de base, c’est le moyen le plus simple de procéder. Cependant, vous devez parfois en savoir plus. La classe Expression de base contient une propriété NodeType à cet effet. Elle retourne un ExpressionType, qui est une énumération des types d’expressions possibles. Une fois que vous connaissez le type du nœud, vous le castez en ce type et effectuer des actions spécifiques. Vous pouvez rechercher certains types de nœuds, puis utiliser les propriétés spécifiques de ce genre d’expression.

Par exemple, ce code imprime le nom d’une variable pour une expression d’accès à la variable. Le code suivant montre la pratique qui consiste à vérifier le type de nœud, à caster en une expression d’accès à la variable, puis à vérifier les propriétés du type d’expression spécifique :

Expression<Func<int, int>> addFive = (num) => num + 5;

if (addFive is LambdaExpression lambdaExp)
{
    var parameter = lambdaExp.Parameters[0];  -- first

    Console.WriteLine(parameter.Name);
    Console.WriteLine(parameter.Type);
}

Créer des arborescences d’expressions

La classe System.Linq.Expression contient également de nombreuses méthodes statiques pour créer des expressions. Ces méthodes créent un nœud d’expression en utilisant les arguments fournis pour ses enfants. De cette façon, vous générez une expression à partir de ses nœuds terminaux. Par exemple, ce code génère une expression Add :

// Addition is an add expression for "1 + 2"
var one = Expression.Constant(1, typeof(int));
var two = Expression.Constant(2, typeof(int));
var addition = Expression.Add(one, two);

Vous pouvez constater d’après cet exemple simple que de nombreux types sont impliqués dans la création et l’utilisation des arborescences d’expressions. Cette complexité est nécessaire pour fournir les fonctionnalités du vocabulaire enrichi fourni par le langage C#.

Il existe des types de nœuds Expression qui mappent à presque tous les éléments de syntaxe du langage C#. Chaque type a des méthodes spécifiques pour ce type d’élément de langage. Cela fait beaucoup de choses à mémoriser en même temps. Plutôt que d’essayer de mémoriser tout, voici les techniques que vous appliquez quand vous travaillez avec des arborescences d’expressions :

  1. Examinez les membres de l’énumération ExpressionType pour déterminer les éventuels nœuds à examiner. Cette liste aide vraiment quand vous souhaitez parcourir et comprendre une arborescence d’expressions.
  2. Examinez les membres statiques de la classe Expression pour générer une expression. Ces méthodes peuvent générer tout type d’expression à partir d’un ensemble de ses nœuds enfants.
  3. Examinez la classe ExpressionVisitor pour générer une arborescence d’expressions modifiée.

Vous trouvez davantage de choses à mesure que vous examinez chacune de ces trois zones. Vous trouvez invariablement ce dont vous avez besoin si vous commencez avec l’une de ces trois étapes.