С# 4 "динамический" в деревьях выражений
Я пытаюсь понять, как собрать все части, и хотел бы оценить конкретный пример исходного кода для простого случая, чтобы начать с.
Рассмотрим следующий код С#:
Func<int, int, int> f = (x, y) => x + y;
Я могу создать эквивалентную функцию во время выполнения с использованием деревьев выражений следующим образом:
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();
Теперь дается следующая лямбда:
Func<dynamic, dynamic, dynamic> f = (x, y) => x + y;
как бы я сгенерировал эквивалент, используя деревья выражений (и, предположительно, Expression.Dynamic
)?
Ответы
Ответ 1
Вы можете создать дерево выражений, которое представляет динамическое выражение добавления С#, передав CallSiteBinder для динамического добавления сложения С# в Expression.Dynamic. Вы можете открыть код для создания связующего, запустив Reflector в исходном динамическом выражении. Ваш пример будет выглядеть примерно так:
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();
Ответ 2
Вы не можете этого сделать, потому что дерево выражений "Не может содержать динамическую операцию".
Ниже не будет компилироваться из-за операции +, и вы пытаетесь построить дерево выражений, которое нарушает это правило:
Expression<Func<dynamic, dynamic, dynamic>> f = (x, y) => x + y;
Если вы не выполняли операцию добавления, вы могли бы с ней справиться.
См. Как создать выражение и lt; Func < dynamic, dynamic → → - Или это ошибка? для получения дополнительной информации.
Edit:
Это как можно ближе, определяя мой собственный метод Add, который принимает динамические параметры и возвращает динамический результат.
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;
}
}
Ответ 3
Очень интересно. Я думаю, это невозможно по той же причине следующее не компилируется:
Expression<Func<dynamic, dynamic, int>> func = (p1, p2) => p1 + p2;
Это ошибка компилятора CS1963 (которая, похоже, не документирована MS):
ошибка CS1963: дерево выражений не может содержать динамическую операцию