web-dev-qa-db-ja.com

C#4式ツリーの「動的」

私はすべての要素を組み合わせる方法を理解しようとしています。簡単なケースから始めるための具体的なソースコードサンプルをいただければ幸いです。

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

50
Pavel Minaev

動的C#追加式のCallSiteBinderをExpression.Dynamicに渡すことにより、動的C#追加式を表す式ツリーを作成できます。元の動的式で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();
54
Quartermeister

式ツリーは「動的な操作を含んでいない可能性がある」ため、これは実行できません。

たとえば、+演算が原因で次のコードはコンパイルされず、そのルールに違反する式ツリーを構築しようとしています。

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

追加操作を行わなかった場合は、それでうまくいくでしょう。

詳細は Expression <Func <dynamic、dynamic >>を作成する方法-またはバグですか? を参照してください。

編集:

これは、動的パラメーターを受け取り、動的な結果を返す独自の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;
    }
}

とても興味深い。同じ理由で以下がコンパイルされないのは不可能だと思います:

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

これはコンパイラエラーCS1963です(これはMSによって文書化されていないようです)。

エラーCS1963:式ツリーに動的操作が含まれていない可能性があります

1
Igor Zevaka