4

Karl Shiffet による「InTheBox」WPF トレーニングを完了しましたが、WPF を学習するための優れたリソースであることがわかりました。取り上げられたことの 1 つは、依存性注入と Unity コンテナーの使用です。これが私にいくつかの疑問を投げかけたコードのセクションです:

public partial class App : Application {

    protected override void OnStartup(StartupEventArgs e) {

        IUnityContainer container = new UnityContainer();

        container.RegisterType<IDialogService, ModalDialogService>(
            new ContainerControlledLifetimeManager());

        container.RegisterType<IEventRepository, EventRepository>(
            new ContainerControlledLifetimeManager());

        MainWindow window = container.Resolve<MainWindow>();

        window.DataContext = container.Resolve<MainWindowViewModel>();

        window.Show();
    }
}

依存関係は UnityContainer に登録され、UnityContainer によって MainWindowViewModel に注入されます。私の質問は、なぜコンテナを使用するのですか? 依存性注入に関する限り、同じことを実現する次のコードを使用してみませんか。

protected override void OnStartup(StartupEventArgs e)
{
    IDialogService dialogService = new ModalDialogService();
    IEventRepository eventRepository = new EventRepository();

    MainWindow window = new MainWindow();
    window.DataContext = 
        new MainWindowViewModel(eventRepository, dialogService);
    window.Show();
}

コンポジションルートからコンストラクターに依存関係を注入しているため、この場合、UnityContainer を使用するメリットはありません。

理由があることは明らかですが、この状況で何かを追加するかどうかを誰かが説明できますか? また、このようなコンテナの使用が本当に簡単である別の状況はありますか?

4

2 に答える 2

5

このような単純なケースで DI コンテナーを使用しても、実際にはあまり役に立ちません。物事がより複雑になると、より意味があり、依存関係の変更の影響も最小限に抑えられます。

たとえば、すべての依存関係が現在使用している ILoggingService があるとします。Unity のような DI コンテナーを使用する場合、コードを 1 行追加するだけです。

    protected override void OnStartup(StartupEventArgs e)
    {
        IUnityContainer container = new UnityContainer();
        container.RegisterType<IDialogService, ModalDialogService>();
        container.RegisterType<IEventRepository, EventRepository>();
        container.RegisterType<ILoggingService, LoggingService>(); // added

        MainWindow window = container.Resolve<MainWindow>();
        window.DataContext = container.Resolve<MainWindowViewModel>();
        window.Show();
    }

自分で行う場合は、1 行のコードを追加し、3 行のコードを変更する必要があります。

    protected override void OnStartup(StartupEventArgs e)
    {
        ILoggingService loggingService = new LoggingService(); // added
        IDialogService dialogService = new ModalDialogService(loggingService); // modified
        IEventRepository eventRepository = new EventRepository(loggingService); // modified

        MainWindow window = new MainWindow();
        window.DataContext = new MainWindowViewModel(eventRepository, dialogService, loggingService); // modified
        window.Show();
    }

登録するタイプをスキャンできる、より高度なコンテナーを使用する場合、コンポジション ルートのコードを変更する必要がない可能性があります。AutoFac を使用した例を次に示します。

    protected override void OnStartup(StartupEventArgs e)
    {
        var builder = new ContainerBuilder();
        var assembly = Assembly.GetExecutingAssembly();
        builder.RegisterAssemblyTypes(assembly)
               .AsSelf()
               .AsImplementedInterfaces();
        var container = builder.Build();

        MainWindow window = container.Resolve<MainWindow>();
        window.DataContext = container.Resolve<MainWindowViewModel>();
        window.Show();
    }
于 2013-06-06T12:42:04.800 に答える
2

あなたは良い点を指摘します。2 番目の例は、Mark Seemann が「貧乏人の DI」と呼んでいるものを使用しています。それはまだDIですが、あなたは自分でやっています。

IoC コンテナーは、多くの異なる型の注入を管理し始めると本領を発揮し、ライフスタイル管理や規則による型の登録などの機能が大幅な労力の節約になります。

あなたが提案したように、最小限の依存関係管理を伴う小さなタスクの場合、それらはおそらくやり過ぎです。

詳細を知りたい場合は、Seemann の本とブログを強くお勧めします。私見、彼はそのトピックを誰よりもうまく説明しています。

于 2013-06-06T10:43:56.380 に答える