2011-08-04 39 views
16

コンストラクタインジェクションを「手動」コンストラクタパラメータと組み合わせるにはどうすればよいですか?すなわち、DIとコンストラクタパラメータを組み合わせる?

public class SomeObject 
{ 
    public SomeObject(IService service, float someValue) 
    { 
    } 
} 

ここで、IServiceはDIコンテナによって解決/注入され、someValueが指定される必要があります。どのように2つを混ぜるのですか?

+0

手動コンストラクタパラメータとは、DIの代わりに手動でクラスを構築するとき、またはDIコンテナがパラメータを渡すことを意味します。その前者なら、あなたはコンストラクタに過負荷をかけることができますか? – lahsrah

+0

私はいつもIServiceが必要な場合は、オーバーロードを行うだけでなく、依存関係を避けることができ、(ServiceLocator-yuckを使用しない限り)魔法のように完全なコンストラクタを使用すると仮定します。 –

答えて

13

@Remo Gloorのソリューション(およびこの種のソリューションを避け再批判的助言)を使用してくださいNB。したがって、このパラメータは実際にコンストラクタの引数として必要ですか?あるいは、SomeObjectは、オブジェクト上で実行するメソッドにパラメータを渡すことによって、それに依存するすべての人が再利用するステートレスなものに置き換えることができますか?

代わりに

public class SomeObject 
{ 
    private float someValue 
    public SomeObject(IService service, float someValue) 
    { 
     this.someValue = someValue 
    } 

    public float Do(float x) 
    { 
     return this.Service.Get(this.someValue) * x; 
    } 
} 

使用の

public class SomeObject 
{ 
    public SomeObject(IService service) 
    { 
    } 

    public float Do(float x, float someValue) 
    { 
     return this.Service.Get(someValue) * x; 
    } 
} 

それが必要な場合は、工場のために行く:

public interface ISomeObjectFactory 
{ 
    ISomeObject CreateSomeObject(float someValue); 
} 

public class SomeObjectFactory : ISomeObjectFactory 
{ 
    private IKernel kernel; 
    public SomeObjectFactory(IKernel kernel) 
    { 
     this.Kernel = kernel; 
    } 

    public ISomeObject Create(float someValue) 
    { 
     return this.kernel.Get<ISomeObject>(WithConstructorArgument("someValue", someValue); 
    } 
} 

はプレビュー: Ninject 2.4はもう実装を必要とするが許可されません

kernel.Bind<ISomeObjectFactory>().ToFactory(); // or maybe .AsFactory(); 
+0

+1間違いなく正解を避け、私の答えを編集して同意する。私はそれがポイントを少し隠すだろうと知っていますが、他の場所で先にカバーされたように、カーネルを直接使うのではなく、Func ctor argであなたのSomeObjectFactoryを表現することを検討してください。 –

+0

@Ruben Bartelink:私はそれが2.4。工場はカーネルによって自動生成されます。 Funcのバリアントは、Funcがパラメータに関する情報を提供せず、パラメータのマッチングをより困難にするという欠点をサポートします。したがって、Funcのバリアントは、ファクトリの実装を削除してバインドを変更するだけで、更新することができません。しかし、私は、消費者の側にあるインタフェースを使っている間に、工場をブートストラップに入れてしまいます。 –

+0

Func injectionの微妙なことを説明してくれてありがとうございました。私は単にあなたの手のインプラントに[2.4がオートジェニックする] Factoryのインプリメントではなく、代わりにFuncを取って取り除くことができるカーネル上のctor depを取っているということを指摘していました。それを考えると、答えはあまり明確ではなく、 'ToFactory'がやろうとしていることには対応しません。だから私が言ったことを忘れて、説明に感謝する!それはsu_gg_estです:P BTWメソッド名をCreate(CreateSomeObjectではなく)として誤って入力しました。私は難読化された世界に住んでいるので、個人的にはFuncを優先的に使用します... –

1

「someValueのは」は常に一定であれば、あなたがしている間、あなたはInjectionParametersを使用して考えることができるが真でない場合、それは以下の記事で

See Here

を説明するように、コンテナであなたのタイプを登録するが、インスタンスを解決する際にパラメータ値を分離する方法がない場合、コンストラクタから 'someValue'を移動してクラスのプロパティにすると考えるかもしれません。

0

私はおそらく、これに単純な解決策を使用します。 someValueの値がわかっている場合は、それをコンストラクタから削除し、オブジェクトにプロパティを追加してsomeValueを設定することができます。この方法では、オブジェクトをコンテナから取得し、そのオブジェクトがあるときに値を設定できます。

他の提案は、直接アクセスする代わりに、そのようなオブジェクトを作成するために使用できるファクトリを作成することです。次に、コンテナにファクトリを登録し、ファクトリを使用してインスタンスを作成します。このようなもの:

public class SomeObjectFactory : ISomeObjectFactory 
{ 
    private IYourService _service; 
    public SomeObjectFactory(IYourService service) 
    { 
     _service = service; 
    } 

    public ISomeObject Create(float someValue) 
    { 
     return new SomeObject(_service, someValue); 
    } 
} 

このようなパターンを試すことができます。

更新:改善のコメントを反映するようにコードを更新しました。

+0

'SomeObjectFactory'で選択したコンテナに強く依存しているようです。これは広く推奨されていません。代わりに、 'IYourService'インスタンスを' SomeObjectFactory'コンストラクタに注入し、conatinerにコンポジションルートの依存関係を解決させます。 –

+0

もちろん、私のコードは単なる概要であり、最終的な実装ではありません。要点は、代わりに工場を使うべきだということです。しかし、私はあなたが意味すると思うようにコードを更新しました。 –

+0

非常に良い! :) –

1

本当にD.I.を使用しないでください。このため。すべての種類の不器用な解決策を思いつくことができますが、道に迷ってしまうかもしれません。

私たちのアプローチは、D.I.でファクトリを作成し、ファクトリのCreateメソッドがD.I.で渡されたものを使用して自身を構築することです。コンテナ。このパターンを頻繁に使用する必要はありませんが、実際に行うと、製品がよりクリーンになります(従属グラフが小さくなるため)。

1

これをタグ付けしたNInjectでは、を使用して、Func<parameters you wish to feed in,T>の形式で自動的に生成されたファクトリを挿入します。

この方法は、自動ファクシミリでも利用できます。

さまざまなFactory method approaches are covered in the answers to this question

EDIT:これは面白いかもしれないが、可能な限り、そのような構築物は避けるべきである