これはServiceLocatorと呼ばれる制御の反転の劣った形式であり、現在の状況で要約できる欠陥があるため、(効果的に)コンテナーを注入しません。最終的にはコンテナーをすべてに注入する必要があります。
代わりに、「このコンポーネントは作成を担当し、それを実行するために何が必要か」という観点から問題に取り組む必要があります。
Lonni-Lokiが述べたように、1つのオプションは完全に形成されたコントロールを注入することですが、その点については同意しません。メインビューにこのサブコンポーネントを作成する責任がある場合は、それを作成する必要がありますが、その責任を促進するには、メインビューにservices/models / etcを挿入し、それを渡すか、そうでなければそれを作成するために使用する必要があります。Autofacのファクトリメソッドスタブはこれに理想的です。
たとえば、サブビューにIFooViewModelが必要な場合は、Func <IFooViewModel <(コンテキストに登録されたファクトリメソッド)をコンテナに挿入できます。これを使用して、新しい包含ビューを「オンデマンドでフィード」できます。
(または、必要に応じて、Func <arg1、arg2など、IFooViewModel>)
便利な経験則の1つは、クラスXを検討するときに、最初に「新しい」ものをどこにでも持っていき、代わりにそれをコンストラクターに渡すことです。次に、コードを見て、「クラスXのインスタンスが必要な場合、コンストラクターに何を渡す必要がありますか?」と自問してください。それらはあなたの依存関係です。
もっと実践的な例を見てみましょう...あなたがこのような構造を持っているとしましょう:
アプリケーションがメインウィンドウを作成します
MainWindowはSubView1を作成し、IMainWindowViewModelが必要です
SubView1にはISubView1Model、IFooServiceが必要です
SubView1はSubView2を作成します
SubView2にはISubView2Model、IBarServiceが必要です
したがって、ctorは次のようになります。
public MainWindow(IMainWindowViewModel viewModel,
Func<SubView1> subView1Factory)
public SubView1(ISubView1Model viewModel,
IFooService fooService,
Func<IFooService, SubView2> subView2Factory)
public SubView2(
ISubView2ModelViewModel viewModel,
IBarService barService)
コンテナを設定すると、次のようになります。
(私はさまざまなIoCコンテナーを使用しているため、Autofac構文が錆びている可能性があることに注意してください)
var builder = new ContainerBuilder();
// Simple bit, register implementations for viewmodel, services
builder.RegisterType<MainWindowViewModel>.As<IMainWindowViewModel>();
builder.RegisterType<SubView1Model>.As<ISubView1Model>();
builder.RegisterInstance<FooService>.As<IFooService>();
// ok, lemme see if I can remember expression syntax...
// Simple case: 'static' resolution of subview
// We want a func that takes no args and returns us a fully-initialized
// SubView1
builder.Register<Func<SubView1>>(context =>
{
// Since all the bits of a subview1 are registered, simply
// resolve it and return
var view = context.Resolve<SubView1>();
return () => view;
});
// Complicated case - lets say this viewmodel depends
// on foo service, which it uses to determine which
// bar service to use
builder.Register<Func<IFooService, SubView2>>(context =>
{
// and our view model
var vm = context.Resolve<ISubView2ViewModel>();
return (service) =>
{
var barService = new BarService(service);
return new SubView2(vm, barService);
};
});
IoCコンテナの輝かしい(そして私の意見では)使用法は、「私がすでに言ったことに基づいてすべてのビットを取得する方法を理解する」部分です。それ以外の場合は、手動インジェクションを使用することをお勧めします。依存関係を手動で渡します。とは言うものの、MainWindowの潜在的に複雑な構造は今では次のようになっています。
container.Resolve<MainWindow>();
コードにタイプミスやエラーが多すぎないことを願っていますが、しばらくの間Autofacを使用していません。