16

Microsoft の Unity フレームワークで C# を使用しています。この問題を解決する方法がよくわかりません。おそらく、Unity での DI を理解していないことが関係していると思われます。

私の問題は、次のコード例を使用して要約できます。

class Train(Person p) { ... }

class Bus(Person p) { ... }

class Person(string name) { ... }

Person dad = new Person("joe");
Person son = new Person("timmy");

バスで解決メソッドを呼び出すと、「ティミー」という名前の人「息子」が注入されたことをどのように確認できますか?また、トレインを解決するときに、「ジョー」という名前の人「お父さん」が解決されたことをどのように確認できますか?

名前付きインスタンスを使用するのではないかと考えていますか?しかし、私は途方に暮れています。どんな助けでも大歓迎です。

余談ですが、私はむしろ IPerson インターフェイスを作成したくありません。

4

3 に答える 3

35

名前付き依存関係として「joe」と「timmy」をそれぞれ登録しない限り、「timmy」が Schoolbus に注入されていることを確認できません。実際、名前のない依存関係として同じクラスの 2 つのインスタンスを登録しようとすると、セットアップが曖昧になり、まったく解決できなくなりますPerson

一般に、多くの名前付きインスタンスを登録する必要がある場合は、おそらく DI を間違った方法で行っている可能性があります。DI の主なアイデアは、ドメイン オブジェクトよりもドメインサービスを解決することです。

DI の主なアイデアは、抽象型(インターフェイスまたは抽象クラス)を具象型に解決できるメカニズムを提供することです。あなたの例には抽象型がないため、あまり意味がありません。

于 2010-01-06T19:21:09.860 に答える
19

これを解決する 1 つの方法は、名前付き登録でインジェクション コンストラクターを使用することです。

// Register timmy this way  
Person son = new Person("Timmy");  
container.RegisterInstance<Person>("son", son);  

// OR register timmy this way  
container.RegisterType<Person>("son", new InjectionConstructor("Timmy"));  

// Either way, register bus this way.  
container.RegisterType<Bus>(new InjectionConstructor(container.Resolve<Person>("son")));  

// Repeat for Joe / Train
于 2010-01-06T19:14:29.773 に答える
15

マーク・シーマンはそれを正しく理解しました。そして、私はあなたの混乱に同情します。自動依存性注入コンテナーの使用法を学んだとき、私は自分でそれを経験しました。問題は、オブジェクトを設計および使用する有効で妥当な方法が多数あることです。しかし、自動依存性注入コンテナーで機能するのは、これらのアプローチの一部のみです。

私の経歴: Unity や Castle Windsor コンテナーなどの Inversion of Control コンテナーの使用方法を学ぶずっと前に、オブジェクト構築のオブジェクト指向の原則と Inversion Of Control を学びました。次のようなコードを書く習慣を身につけました。

public class Foo
{
   IService _service;
   int _accountNumber;

   public Foo(IService service, int accountNumber)
   {
      _service = service;
      _accountNumber = accountNumber;
   }
   public void SaveAccount()
   {
       _service.Save(_accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service(),1234);
        foo.Save();
     }
}

この設計では、Foo クラスがアカウントをデータベースに保存する役割を果たします。それを行うには口座番号が必要であり、汚い仕事をするためのサービスが必要です。これは、各オブジェクトがコンストラクターでいくつかの一意の値を取る、上で提供した具象化されたクラスにいくぶん似ています。これは、独自のコードでオブジェクトをインスタンス化する場合にうまく機能します。適切なタイミングで適切な値を渡すことができます。

しかし、自動依存性注入コンテナーについて知ったとき、もはや手動で Foo をインスタンス化していないことに気付きました。コンテナーは、コンストラクターの引数をインスタンス化します。これは、IService のようなサービスにとって非常に便利でした。しかし、整数や文字列などではうまく機能しないことは明らかです。そのような場合、デフォルト値 (整数のゼロなど) が提供されます。代わりに、アカウント番号、名前などのコンテキスト固有の値を渡すことに慣れていました...そのため、コーディング スタイルとデザインを次のように調整する必要がありました。

public class Foo
{
   IService _service;
   public Foo(IService service)
   {
      _service = service;
   }
   public void SaveAccount(int accountNumber)
   {
       _service.Save(accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service());
        foo.Save(1234);
     }
}

両方の Foo クラスが有効な設計であるように見えます。ただし、2 番目は自動依存性注入で使用できますが、1 番目は使用できません。

于 2010-09-04T11:41:12.893 に答える