web-dev-qa-db-fra.com

C # 4 "dynamique" dans les arbres d'expression

J'essaie de comprendre comment assembler toutes les pièces et souhaiterais un exemple concret de code source pour un cas simple.

Considérez le code C # suivant:

Func<int, int, int> f = (x, y) => x + y;

Je peux produire une fonction équivalente au moment de l'exécution en utilisant des arbres d'expression comme suit:

var x = Expression.Parameter(typeof(int), "x");
var y = Expression.Parameter(typeof(int), "y");
Func<int, int, int> f =
    Expression.Lambda<Func<int, int, int>>(
        Expression.Add(x, y),
        new[] { x, y }
    ).Compile();

Maintenant, étant donné le lambda suivant:

Func<dynamic, dynamic, dynamic> f = (x, y) => x + y;

comment pourrais-je générer l'équivalent en utilisant des arbres d'expression (et vraisemblablement Expression.Dynamic)?

48
Pavel Minaev

Vous pouvez créer une arborescence d'expression qui représente une expression d'addition C # dynamique en transmettant le CallSiteBinder pour une expression d'addition C # dynamique à Expression.Dynamic. Vous pouvez découvrir le code pour créer le classeur en exécutant Reflector sur l'expression dynamique d'origine. Votre exemple ressemblerait à ceci: 

var x = Expression.Parameter(typeof(object), "x");
var y = Expression.Parameter(typeof(object), "y");
var binder = Binder.BinaryOperation(
    CSharpBinderFlags.None, ExpressionType.Add, typeof(Program),
    new CSharpArgumentInfo[] { 
        CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), 
        CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)});
Func<dynamic, dynamic, dynamic> f =
    Expression.Lambda<Func<object, object, object>>(
        Expression.Dynamic(binder, typeof(object), x, y),
        new[] { x, y }
    ).Compile();
53
Quartermeister

Vous ne pouvez pas le faire car un arbre d'expression "ne peut pas contenir d'opération dynamique".

Ce qui suit ne sera pas compilé, à cause de l'opération +, par exemple, et que vous essayez de créer un arbre d'expression qui ne respecte pas cette règle:

 Expression<Func<dynamic, dynamic, dynamic>> f = (x, y) => x + y;

Si vous n'étiez pas en train d'ajouter une opération, vous pourriez vous en tirer.

Voir Comment créer une expression <Func <dynamique, dynamique >> - Ou s'agit-il d'un bogue? pour plus d'informations.

Modifier:

Ceci est aussi proche que possible, en définissant ma propre méthode Add qui prend des paramètres dynamiques et renvoie un résultat dynamique.

    class Program
{
    static void Main(string[] args)
    {

        var x = Expression.Parameter(typeof(object), "x");
        var y = Expression.Parameter(typeof(object), "y");
         Func<dynamic, dynamic, dynamic> f =
             Expression.Lambda<Func<dynamic, dynamic, dynamic>>(
                 Expression.Call(typeof(Program), "Add", null, x, y),
                 new[] { x, y }
             ).Compile();

       Console.WriteLine(f(5, 2));
       Console.ReadKey();
    }

    public static dynamic Add(dynamic x, dynamic y)
    {
        return x + y;
    }
}
1
Richard Hein

Très intéressant. Je suppose que c'est impossible pour la même raison, les éléments suivants ne sont pas compilés:

Expression<Func<dynamic, dynamic, int>> func = (p1, p2) => p1 + p2;

C'est une erreur de compilation CS1963 (qui ne semble pas avoir été documentée par MS):

erreur CS1963: un arbre d'expression ne peut pas contenir d'opération dynamique

0
Igor Zevaka