50 votes

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

J'essaie de comprendre comment assembler tous les éléments et j'apprécierais un exemple concret de code source pour un cas simple afin de commencer.

Considérons 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();

Etant donné le lambda suivant :

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

comment générer l'équivalent à l'aide d'arbres d'expression (et, vraisemblablement, Expression.Dynamic ) ?

55voto

Quartermeister Points 24729

Vous pouvez créer un arbre d'expression qui représente une expression d'addition C# dynamique en passant le CallSiteBinder d'une expression d'addition C# dynamique dans Expression.Dynamic. Vous pouvez découvrir le code de création du Binder en exécutant Reflector sur l'expression dynamique originale. 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();

2voto

Richard Hein Points 6697

Vous ne pouvez pas le faire parce qu'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 vous essayez de construire un arbre d'expression qui viole cette règle :

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

Si vous ne faisiez pas d'opération Add, vous pouviez vous en tirer.

Voir Comment créer une Expression<Func<dynamique, dynamique>> - Ou est-ce un bug ? pour plus d'informations.

Editer :

Je ne peux pas faire mieux, 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;
    }
}

1voto

Igor Zevaka Points 32586

Très intéressant. Je suppose que c'est impossible pour la même raison que ce qui suit ne se compile pas :

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

Il s'agit d'une erreur de compilation CS1963 (qui ne semble pas être documentée par MS) :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X