C # 4 "динамический" в деревьях выражений - PullRequest
49 голосов
/ 25 августа 2010

Я пытаюсь выяснить, как собрать все части вместе, и был бы признателен за конкретный пример исходного кода для простого случая, с которого можно начать.

Рассмотрим следующий код C #:

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

Ответы [ 3 ]

54 голосов
/ 28 августа 2010

Вы можете создать дерево выражений, которое представляет динамическое сложное выражение C #, передав CallSiteBinder для динамического сложного выражения C # в Expression.Dynamic. Вы можете найти код для создания Binder, запустив 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 голосов
/ 25 августа 2010

Вы не можете сделать это, потому что дерево выражений «Может не содержать динамическую операцию».

Следующее не скомпилируется, например, из-за операции +, и вы пытаетесь построить дерево выраженийчто нарушает это правило:

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

Если вы не выполняли операцию добавления, вам это сойдет с рук.

См. Как создать выражение> - Или это ошибка? для получения дополнительной информации.

Редактировать:

Это настолько близко, насколько я могу определить, определяя мой собственный метод 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;
    }
}
1 голос
/ 25 августа 2010

Очень интересно. Я думаю, это невозможно по той же причине, что не компилируется следующее:

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

Это ошибка компилятора CS1963 (которая, похоже, не документирована MS):

ошибка CS1963: дерево выражений может не содержать динамическую операцию

...