0

依存性注入を使用するアプリケーションがありますが、現在IoCコンテナは使用されていません。私はIoCコンテナを紹介したいと思い、私のアプリのセットアップコードの複雑さを低減し、メンテナンス性を向上させるために、IoCコンテナは、複数のタイプのインスタンス(.NET)で自動配線します

ISimpleDependency ez = new SimpleDependency(); 
ISomeOtherDependency otherDep = new SomeOtherDependency(); 

FooConfig fooConfigA = Settings.Default.FooConfigA; 
FooConfig fooConfigB = Settings.Default.FooConfigB; 

IFoo fooA = new Foo(fooConfigA, ez); 
IFoo fooB = new Foo(fooConfigB, ez); 

Bar bar = new Bar(fooA, otherDep); 
Baz baz = new Baz(fooB, ez, otherDep); 
Qux qux = new Qux(fooA, fooB); //params IFoo[] constructor to which we want to pass every Foo 

:私は現在、私のアプリのセットアップコードに次のようなものを持っています。 Fo/Bar/Baz/QuxクラスをIoCコンテナの実装の選択に強固に結合することなくすべて自動配線するためにIoCコンテナを使用できる方法はありますか?

+1

[Unity](https://msdn.microsoft.com/en-us/library/ff649564.aspx)IoCコンテナはサンプルコードと互換性がありますが、IoCコンテナはそれを単純化することができます。 –

+0

質問に含まれているタイプよりも具体的なニーズが少ない他の依存関係がある場合は、プロジェクト全体を単純化しないとは限りません。 –

+0

[this](http://blog.ploeh.dk/2012/11/06/WhentouseaDIContainer/)と[this](https://simpleinjector.org/blog/2015/12/when-should-you)をお読みください。 -use-a-container /)。すべてのアプリケーションがDIコンテナを使用する利点はありません。 – Steven

答えて

1

あなたはIOCコンテナに結合されたセットアップコードで終わるでしょうが、それは問題ありません。重要な点は、セットアップは常にアプリケーションのコンポジションルートで行われることです。つまり、クラスが使用される前に、アプリケーションの起動時に依存関係が指定されます。クラス自体は、コンテナの認識や依存関係の作成方法を意識することなく動作します。

これらはあなたのFooクラスとインタフェースしていると仮定します。

public interface IFoo { } 

public interface IFooConfig { } 

public class Foo : IFoo 
{ 
    private readonly IFooConfig _config; 

    public Foo(IFooConfig config) 
    { 
     _config = config; 
    } 
} 

public class FooConfigA : IFooConfig { } 

public class FooConfigB : IFooConfig { } 

ここではいくつかのコンテナコードです。ご覧のとおり、複雑になります。あなたの依存関係が小さくてシンプルであれば、それは価値がないかもしれません。

例としてWindsorを使用すると、設定は次のようになります。それを行う方法は2つ以上ありますので、より簡単かどうかを判断しておきます。

container.Register(
    Component.For<IFooConfig, FooConfigA>().Named("FooConfigA"), 
    Component.For<IFooConfig, FooConfigB>().Named("FooConfigB"), 
    Component.For<IFoo, Foo>() 
     .DependsOn(Dependency.OnComponent<IFooConfig, FooConfigA>()).Named("FooA") 
     .IsFallback(), 
    Component.For<IFoo, Foo>() 
     .DependsOn(Dependency.OnComponent<IFooConfig, FooConfigB>()).Named("FooB")); 

IFooという名前の2つの登録があります。それぞれが同じタイプのオブジェクト(Foo)を返しますが、それらのインスタンスのそれぞれの実装はIFooConfigurationです。

それとも、Settings.Defaultから来IFooConfigのインスタンスを使用している場合、あなたはこれを行うだろう:

Component.For<IFoo, Foo>() 
    .DependsOn(Dependency.OnValue("config", Default.Settings.FooConfigA)) 
    .Named("FooA") 
    .IsFallback(), 
Component.For<IFoo, Foo>() 
    .DependsOn(Dependency.OnValue("config", Default.Settings.FooConfigB)) 
    .Named("FooB"), 

は今IFooに依存し、各クラスのためにあなたが名前によってどのバージョンあなたを指定することもあるだろう取得するか、それはフォールバックとして指定されているので、あなたはちょうど "A"を取得します。

ご覧のとおり、これはすぐに乱雑で複雑になります。可能であれば、抽象ファクトリを使用して、依存関係の各組み合わせに対してIFooの個別の登録を行う代わりに、実行時に実装を選択する方法もあります。 Here's some more explanation and an example.

あなたはウィンザー(と私は他のコンテナが同様の行動を持っていると確信している)を使用している場合は、IEnumerable<IFoo>Foo[]を取るコンストラクタを持つことができ、その後、ウィンザーはすべて実装を解決し、コンストラクタに渡します。あなたは、コンテナのセットアップにこれを追加します。

container.Kernel.Resolver.AddSubResolver(new ListResolver(container.Kernel, true)); 
+1

これを見て、それをトップのコードと比較すると、私はそれを本当に売っていないと言います。このようなものはすごく便利ですが、複雑さを管理するためのツールです。それは複雑さを解決しません、それはあなたがそれに対処する必要がないときにあなたの髪のそれを保つために他のどこかに移動します。しかし、複雑さを管理することで実際に複雑さが増すと、その価値は疑わしいものになります。 –

+0

注:FooConfigクラスは1つしかなく、インスタンスは2つあります。別々のFooConfigAクラスとFooConfigBクラスはありません。 また、FooにはFooConfig以外の依存関係があり、BarとBazにはFoo以外の依存関係があります。 – Katie

+0

私はそれを正しく追跡しているかどうかはわかりませんでした。だから、これがすべて一般的なものであることは良いことです。登録された型がない場合は、依存関係の値を指定する必要があります。したがって、コンテナにすでに他のタイプのコンポーネントが登録されている場合は、それらのコンポーネントが自動的に解決されます。これは、DIコンテナを有用なものにする大きな要素です。いくつかの学習曲線がありますが、それを完全に使用すれば、より簡単に生活できます。 –

1

シンプルインジェクタを使用する場合は、以下の登録があなたの現在のPure DIアプローチと同等です:

var container = new Container(); 

container.Register<ISimpleDependency, SimpleDependency>(); 
container.Register<ISomeOtherDependency, SomeOtherDependency>(); 
container.Register<Bar>(); 
container.Register<Baz>(); 
container.Register<Qux>(); 

var fooAReg = Lifestyle.Transient.CreateRegistration<IFoo>(
    () => new Foo(Settings.Default.FooConfigA, container.GetInstance<ISimpleDependency>()), 
    container); 

var fooBReg = Lifestyle.Transient.CreateRegistration<IFoo>(
    () => new Foo(Settings.Default.FooConfigB, container.GetInstance<ISimpleDependency>()), 
    container); 

// The registrations for IFoo are conditional. We use fooA for Bar and fooB for Baz. 
container.RegisterConditional(typeof(IFoo), fooAReg, 
    c => c.Consumer.ImplementationType == typeof(Bar)); 
container.RegisterConditional(typeof(IFoo), fooBReg, 
    c => c.Consumer.ImplementationType == typeof(Baz)); 

container.RegisterCollection<IFoo>(new[] { fooAReg, fooBReg }); 

この例では、自動を使用していないことに注意してください。すべての登録の配線。 Foo登録は手動で配線されます。これは、(安全対策として)シンプルインジェクタはコールグラフをその直接の親を越えて 'ルックアップ'することができないため、誤った結果につながる可能性があるからです。このため、自動配線を使用してをFooBarに注入できないのはこのためです。

UPDATE

私はFooConfigB

var fooAProd = Lifestyle.Transient.CreateProducer<IFoo>(
    () => new Foo(Settings.Default.FooConfigA, container.GetInstance<ISimpleDependency>()), 
    container); 

var bar1Reg = Lifestyle.Transient.CreateRegistration<Bar>(() => new Bar(
    fooAProd.GetInstance(), 
    container.GetInstance<IOtherDep1>())); 

var fooBProd = Lifestyle.Transient.CreateProducer<IFoo>(
    () => new Foo(Settings.Default.FooConfigB, container.GetInstance<ISimpleDependency>()), 
    container); 

var bar2Reg = Lifestyle.Transient.CreateRegistration<Bar>(() => new Bar(
    fooBProd.GetInstance(), 
    container.GetInstance<IOtherDep1>())); 

// The registrations for IFoo are conditional. We use fooA for Bar and fooB for Baz. 
container.RegisterConditional(typeof(IFoo), fooBProd.Registration, 
    c => c.Consumer.ImplementationType == typeof(Baz)); 

container.RegisterCollection<IFoo>(new[] { fooAReg, fooBReg }); 
ではFooに依存する2つのFooConfigAではFooに依存一つはバーのインスタンス、および他のを持っている場合はどう

+0

Barのインスタンスが2つある場合、そのうちの1つはFooConfigAでFooに依存し、もう1つはFooConfigBでFooに依存しますか? Castle Windsorを使ってきれいに配線することができましたが、SimpleInjectorやその他の軽量コンテナで動作させる方法を見つけることができませんでした。 – Katie

+0

@Katie:私の更新を見る – Steven

関連する問題