expression.bindとexpression.assignの違いは何ですか(または:MemberBindingについて特別なもの)

c# expression-trees

質問

だから、これはナットとボルトに入っていますが、私はここの誰かが洞察力を持っていることを望んでいます。

ここで私が集めることができたことがあります(もちろん、私はそれについて間違っているかもしれませんが、私を修正してください)

Expression.Bind

[トピック] [1]のMSDN Entryを含む私の研究に基づいて、Expression.BindメソッドはMemberBinding式の特定のサブタイプであるMemberAssignment型の式を生成するために使用されるようです。このメソッドは、MemberInfoとそれがバインドされるべき式を取ります。結果として得られるMemberAssignment式は、メンバーの初期化を表します。

Expression.Assign

割り当て操作を表すBinaryExpressionを作成するメソッドです。

Expression.MemberInitメソッドへのバインディングを提供するときにExpression.Assignを使用するのはなぜですか?の代わりに:

    MemberAssignment binding = Expression.Bind(PropAccessMethodInfo, TargetExpression)

たとえば、次のようにします。

    MemberExpression getProperty = Expression.Property(FindObjectExpression, PropAccessMethodInfo)
    Expression binding = Expression.Assign(getProperty, TargetExpression)

私はコンパイラが不平を言うことを知っていますが、ここでは構文上の問題以上のものがあるかどうか尋ねています。 別の言い方をすれば、Expression.Bind / MemberBindingsは私たちに何か追加を与えますか?それとも、メンバーの初期化を簡単に管理できる構文上の砂糖ですか?

さらに具体的には、.NET EF4のビジネスオブジェクトと基礎となるエンティティとの関係を把握するのに役立つでしょうか。 Entity Frameworkの "Working with Proxies"にどういうふうに合っているのですか、または変更トラッキングやビジネスオブジェクトとEFベースのデータアクセスレイヤーの間の橋渡しに役立ちますか?

おそらく予見できるように、私は基本的なコンポーネントのエンティティとそのような式(特にMemberInitメソッド)から自分のビジネスオブジェクトの作成をプログラマチックに配線しようとしていますが、確かに作成ビットを助けることができます。

しかし、EF / .NETがこれらのバインディングを使用して追跡するのに十分なほどスマートなのかどうかは不明でした。または、私はそれらの同じバインディングをBiz < - >エントリー追跡/ブリッジに再利用できるかどうか。

私はそれが理にかなったことを望む。不明な点がある場合は、より多くの情報をお寄せいただきます。

ありがとう!!

受け入れられた回答

オブジェクトイニシャライザは複雑な構文砂糖です... ILレベルでオブジェクトイニシャライザに似ているものがないので構文砂糖だけです...特別な指示はありません... C#コンパイラだけが命令を特定のOIを使用せずに同じコードを書くことができます。残念ながら、この糖の正確な働きはまれにしか説明されていません。

そして今、なぜそれが複雑な統語的砂糖なのかをお見せしましょう!

あなたはこれを考えることができます:

foo = new Foo { Bar = 5 };

翻訳された

foo = new Foo();
foo.Bar = 5;

しかし実際には、それはそうではないことを知っています... fooはプロパティです...確かに2回アクセスされません( new Foo()を保存するための1つの書き込みとfoo.Barにアクセスするための1つの読み取り) ..

だからコードはこれと同じでなければならない。

Foo tmp = new Foo();
foo = tmp;
tmp.Bar = 5;

しかし、実際にはそうではありません!おそらくもっと似ています

Foo tmp = new Foo();
tmp.Bar = 5;
foo = tmp;

違いは、 Foo.Barのセッターが例外をスローすると、 fooはセットされないということです!

あなたはそれを試すことができます: http : //ideone.com/PjD7zF

ソースコード:

using System;

class Program
{
    class Foo
    {
        public Foo()
        {
            Console.WriteLine("Building Foo");
        }

        public int Bar
        {
            get
            {
                Console.WriteLine("Getting Foo.Bar");
                return 0;
            }

            set
            {
                Console.WriteLine("Setting Foo.Bar: boom!");
                throw new Exception();
            }
        }
    }

    static Foo foo2;

    static Foo foo
    {
        get
        {
            Console.WriteLine("Getting foo");
            return foo2;
        }

        set
        {
            Console.WriteLine("Setting foo");
            foo2 = value;
        }
    }

    static void Main(string[] args)
    {
        try
        {
            foo = new Foo { Bar = 100 };

            // Not executed, only to disassemble and check 
            // that it isn't using special instructions!
            foo = new Foo();
            foo.Bar = 200;
        }
        catch (Exception ex)
        {
            Console.WriteLine("Exception: {0}", ex);
        }

        Console.WriteLine("Finished try/catch");

        Console.WriteLine("foo initialized: {0}", foo != null);
    }
}

構文的な砂糖の複雑さに加えて、このような些細な違いは、確かにこれだけのために構築された "特別な" ExpressionExpression.MemberInit )を作成するのに十分なものです。

Expression.Bindは、オブジェクトイニシャライザの動作を正確にシミュレートする必要があり、オブジェクト初期化子で新しいオブジェクトの "this"にアクセスできないため、必要です。あなたは書くことはできません:

// wrong
foo = new Foo { this.Bar = 5 };

彼らはあなたが次のような表現を書くことを望んでいなかった。

foo = new Foo { somethingElse.Prop = 10 } 

Expression.MemberInit単純にExpression.Assign配列を受け入れた場合には可能です。

第二の点は... Expression.MemberInit 、.NET 3.5である(とメンバーの初期化が非常にLINQで使用されるものですので、それは必要だ)、 Expression.Assign唯一の.NET 4.0です。式ツリーは、LINQ(少なくともLINQからオブジェクトへのLINQからオブジェクトへのLINQは式ツリーを使用しないため)で作成および構築されました。 Expression.Assignは必要ではなく、実装されていませんでした。 Expression.MemberInitが必要なので、実装されました。

3番目のポイント...メンバの初期化はLINQではかなり一般的なものなので、メンバ初期化(一時変数、いくつかの代入など)の "基本"部分からすべての式を構築する必要はありませんでしたデバッグ時の式は、あらかじめ作成された「オールインワン」の方法よりも複雑です)。

第4のポイント... LINQプロバイダは、通常、可能なすべてのExpression実装しておらず、完全に異なる環境で式をリモートで実行する必要があります(LINQ-to- SQL Server上でLINQクエリを実行するSQL)。 Expression.MemberInitはるかに制限さよりもExpression.Assignので、LINQプロバイダによって実装することが容易です。

だから、これらの理由のいくつかを選んでください...彼らはすべてかなり良いです、そしておそらくそれらのどれか一つだけで Expression.MemberInitを実装することを決定するのに十分でしょう。一緒に4人?



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ