2011-09-17 29 views
6

私は何かが分かりにくいと感じています。私はここでいくつかの関連する質問を読みました。そして、私はNinjectのwikiの更新されたコンテキストバインディングページを読んだのですが、うまくいきません。WhenInjectedInto拡張メソッドを使用したバインドバインド

Ninjectを使用するために工場パターンを使用していたレガシーアプリケーションを改造しようとしています。

私は2つのクラス(ClassBとClassC)で実装された1つのインタフェース(IInterface)を持っています。 IInterfaceにはロードメソッドがあります。 ClassBのロードメソッドでは、ClassCをインスタンス化してからロードメソッドを実行します。

基本的に、プログラムフローはClassAでClassBを作成し、ロードメソッドを実行します。ロードメソッドでは、ClassBは何らかの作業を行うClassCを作成します。

私のバインディングが

エラーが一致するバインディングが用意されていないメソッドはIInterface活性化

Bind<IInterface>().To<ClassC>().WhenInjectedInto<ClassB>(); 
Bind<IInterface>().To<ClassB>().WhenInjectedInto<ClassA>(); 

これは、それがこのエラーでClassBののloadメソッドに失敗した実行さ

... ...セットアップようにしており、タイプは自己バインドできません。

私は、次の...

Bind<IInterface>().To<ClassC>().WhenInjectedInto<ClassB>(); 
Bind<IInterface>().To<ClassB>(); 

をしようとするとそれは無限ループを実行し、決してクラスCを作成します。私はパスしたが、私が望む結果が得られていないユニットテストにこれを単純化している

EDIT ...

[TestClass] 
public class NinjectTestFixture 
{ 
    private interface IDoSomething 
    { 
     void SaySomething(); 
    } 

    private class ClassA : IDoSomething 
    { 
     public void SaySomething() 
     { 
      Console.WriteLine("Hello from Class A"); 
     } 
    } 

    private class ClassB : IDoSomething 
    { 
     private IKernel _Kernel; 

     public ClassB(IKernel kernel) 
     { 
      _Kernel = kernel; 
     } 

     public void SaySomething() 
     { 
      Console.WriteLine("Hello from Class B"); 

      var x = _Kernel.Get<IDoSomething>(); 

      x.SaySomething(); 
     } 
    } 

    private class ClassC 
    { 
     private IKernel _Kernel; 

     public ClassC(IKernel kernel) 
     { 
      _Kernel = kernel; 
     } 

     public void SaySomething() 
     { 
      Console.WriteLine("Hello from Class C"); 

      var x = _Kernel.Get<IDoSomething>(); 

      x.SaySomething(); 
     } 
    } 

    [TestMethod] 
    public void TestMethod1() 
    { 
     var kernel = new StandardKernel(); 

     kernel.Bind<IDoSomething>().To<ClassA>(); 
     kernel.Bind<IDoSomething>().To<ClassB>().WhenInjectedInto<ClassC>(); 
     kernel.Bind<ClassC>().ToSelf(); 

     var x = kernel.Get<ClassC>(); 

     x.SaySomething(); 
    } 

出力は次のとおりです。クラスC から こんにちはHelloクラスA

しかし、私は欲しい: HelloクラスC こんにちはクラスB こんにちはクラスA

おかげ

答えて

6

あなたはクラスCに注入ないです。あなたはカーネルを渡してIDoSomethingを直接解決しています。大きな違いがあります。

カーネルをパラメータとして渡さないでください。そうすることで、依存関係注入はサービスロケーションです(差異に関する良い記事:Service Locator is an Anti-Pattern)。

変更クラスCがなければ:

private class ClassC  
{   
    private IDoSomething _doSomething;   
    public ClassC(IDoSomething doSomething) 
    {    
     _doSomething = doSomething;   
    }   

    public void SaySomething()   
    {    
     Console.WriteLine("Hello from Class C");    
     //var x = _Kernel.Get<IDoSomething>();    
     _doSomething.SaySomething();   
    }  
} 

またにClassAとClassBの(カーネル、あなたが解決したいタイプ/インタフェースを通過していない)にも同じ変更を行う必要があります。

+0

私はあなたが言っていることを理解していますが、SaySomethingメソッドでは、いくつかの作業を行うためにオブジェクトをインスタンス化する必要があります。同じクラスには、より多くの作業を行うメソッドをインスタンス化する他のメソッドがあります。私があなたが提案していることをしたなら、私のコンストラクタには約20のパラメータがあります。コードはもともと6年以上前に書かれていたので、徐々にDIを改造しようとしています。私はこれを行う方法に頭を悩まし、カーネルを通すことが最も理にかなった最も簡単な解決策でした。私はサービスの場所を探していましたが、現在のコードベースでは意味がありませんでした。 – oliwa

+0

あなたは正しい答えです。あなたが提案した変更を加えたとき、私は期待した結果を得ました。 – oliwa

+0

私はあなたが何を意味するのか - 私はDIを導入するために奇妙で醜い暫定的なステップを使わなければならないシステムをリファクタリングしました。 –

関連する問題