C#と諸々

C#がメインで他もまぁ諸々なブログです
おかしなこと書いてたら指摘してくれると嬉しいです(´・∀・`)
つーかコメント欲しい(´・ω・`)

2008/06/19 00:54
データマッパー (PofEAA) がドメインオブジェクトをロードする際、リッチコンストラクタを用いることで最初から完成されたドメインオブジェクトを生成することができる。すると、ロードのためだけにセッターを提供したりする必要がないため、スマートなインターフェイスを実現できる。
しかし、循環参照を伴うドメインオブジェクトでは、リッチコンストラクタの使用に問題が生じる。
例えば、次の Hoge クラスと Fuga クラスのような場合だ。

class Hoge
{
    readonly Fuga _f;
    public Hoge(Fuga f)
    {
        if (f == null)
        {
            throw new ArgumentNullException("f");
        }
        this._f = f;
    }
}

class Fuga
{
    readonly Hoge _h;
    public Fuga(Hoge h)
    {
        if (h == null)
        {
            throw new ArgumentNullException("h");
        }
        this._h = h;
    }
}

Hoge のコンストラクタでは Fuga のインスタンスを必要とする。Fuga のコンストラクタでは Hoge のインスタンスを必要とする。これは通常、決してインスタンス化することができない。
しかし、.NET では、コンストラクタを呼び出さずにインスタンス化することができる。そして、リフレクションを使用すればコンストラクタを後から呼び出すこともできる。
つまり、次のようなコードでリッチコンストラクタの循環参照問題は克服できる。

// using System;
// using System.Runtime.Serialization;
// using System.Reflection;

Hoge h = (Hoge)FormatterServices.GetUninitializedObject(typeof(Hoge));
Fuga f = new Fuga(h);
ConstructorInfo ctor = typeof(Hoge).GetConstructor(new[] { typeof(Fuga) });
ctor.Invoke(h, new[] { f });

なお、コンストラクタを後から呼び出す代わりに、リフレクションで直接フィールドを設定するという方法も取れる。しかし、直接フィールドを設定する理由はないし、メリットもない。むしろ、循環参照の問題さえなければ普通にリッチコンストラクタでインスタンス化しているわけなのだから、リッチコンストラクタを使うべきだろう。











トラックバックURL↓
http://csharper.blog57.fc2.com/tb.php/220-e0ac09af