2011-10-31 12 views
8

私はサービスの複数の実装をバインドすると、一度に呼ばれるそれらのすべてを持っている:Ninjectマルチキャスト

var kernel = new StandardKernel(); 

kernel.Bind<IBreakfast>.To<Spam>(); 
kernel.Bind<IBreakfast>.To<Eggs>(); 
kernel.Bind<IBreakfast>.To<MoreSpam>(); 

kernel.Get<IBreakfast>().Eat(); // call Eat method on all three bound implementations 

Ninjectはそれを好きではない、と複数のバインディングを持っていることについて例外がスローされます。そのエラーを回避し、すべての実装を呼び出す方法がありますか?

Bind<>また、実行時にロードされる場合とロードされない場合があるため、呼び出しを行うための単一の実装を作成することはできません。これは、ASP.NET MVC 3 Webサイトのプラグインアーキテクチャの一部です。

答えて

12

コンストラクタインジェクションを使用し、List<IBreakfast>パラメータを持つ場合、Ninjectはすべてのバインディングを使用してリストを作成します。これらのインスタンスでEatに電話をかけることができます。

このパターンを使用すると、Ninjectにプラグインのリストを作成させることができます。

[Test] 
    public void Test() 
    { 
     IKernel kernel = new StandardKernel(); 

     kernel.Bind<IBreakfast>().To<Eggs>(); 
     kernel.Bind<IBreakfast>().To<Spam>(); 
     kernel.Bind<IBreakfast>().To<MoreSpam>(); 

     var bling = kernel.Get<Bling>(); 
    } 

    private class Bling 
    { 
     public Bling(List<IBreakfast> things) 
     { 
      things.ForEach(t => t.Eat()); 
     } 
    } 

    private interface IBreakfast 
    { 
     void Eat(); 
    } 

    private class Ingrediant : IBreakfast 
    { 
     public void Eat(){Console.WriteLine(GetType().Name);} 
    } 

    private class Eggs : Ingrediant{} 
    private class Spam : Ingrediant{} 
    private class MoreSpam : Ingrediant { } 

出力:


スパム
MoreSpamが

+0

(>私は仕事を得るとき、私は午前中にこれをみますが、Ninjectは、 'バインド<2番目の呼び出しでエラーがスローされません).To <>() '? – MikeWyatt

+5

@MikeWyatt:いいえ、複数の「バインド」は問題ありません。良くない点は、 'Get 'が 'Single'以上の項目を生成することです。 'GetAll '(または 'List '、 'T []'、または 'IEnumerable 'を使って複数の登録を暗黙的にバッチアップすることができます)テストが爆発するものはまだ載せていないからです!)。 Ninjectは暗黙のコンポジットを生成して、あなたが望むやり方で呼び出しをマルチキャストすることは何もありません。 –

+1

これは素晴らしいです。ありがとう。 – MikeWyatt

0

あなたは多くの具体的なクラスに一度、単一のインターフェースをバインドすることはできません、それはDIのルール違反です。

基本的には、具体的なインスタンスのカップルを初期化し、そのメソッドを呼び出すことです。あなたはこれをチェックすることもできます

Bind<IBreakfast>.To<Spam>().Named("Spam"); 
Bind<IBreakfast>.To<Eggs>().Named("Eggs"); 
Bind<IBreakfast>.To<MoreSpam>().Named("MoreSpam"); 

var breakfastList = new List() { "Spam", "Eggs", "MoreSpam" }; 
breakfastList.ForEach(item => kernel.Get<IBreakfast>(item).Eat()); 
+0

DIルールに違反しているとは言いません。あなたの問題のドメインが、インターフェイスと具体的なクラスの間に潜在的に1対多の関係が常に存在する場合、それは問題ありません。まともなIoCコンテナでこのシナリオをモデル化できます。 OPのプラグインシナリオは、これらのタイプのモデルの1つです。 –

+3

このアプローチはプラグインアーキテクチャでは機能しません。なぜなら、定義上、どのプラグインが存在するのかわからないからです。 – Bevan

関連する問題