Подтвердить что ты не робот

С# 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)?

4b9b3361

Ответ 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: дерево выражений не может содержать динамическую операцию