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
)?
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();
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;
}
}
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