使用具有运行时相关构造函数参数的IoC / DI容器

时间:2016-05-16 13:12:44

标签: c# dependency-injection structuremap

我将我的代码转换为使用带有StructureMap的IoC容器。试着把事情弄清楚,我觉得它已经开始点击了#39;我可以看到它对后端方面有多大意义。

但是,我正在努力工作,我发现了一些注意事项,我不知道如何让它发挥作用。具体来说,我的原始构造函数做了一些重要的事情,其中​​一个参数不是一个依赖项,或者是一些在运行时会发生变化的东西。

让我们说我从这个(IoC前容器)开始,我使用构造函数传递我的依赖项,但也发送了ImportantObject依赖于运行时的:{ / p>

IMyPageViewModel myPageViewModel = new MyPageViewModel(importantObject, dialogManager, pageDisplay, viewModelProvider)

这里正在进行构建:

public MyPageViewModel(ImportantObject importantObject, IDialogManager dialogManager,IPageDisplay pageDisplay, IViewModelProvider viewModelProvider)
{
    this.dialogManager = dialogManager;
    this.pageDisplay = pageDisplay;
    this.viewModelProvider = viewModelProvider;

    importantObject.DoThatImportantThing();
}

现在,我正在迁移使用IoC容器,起初我觉得我应该这样做:

//I need to create an instance to use, so I use my IoC container:
IMyPageViewModel myPageViewModel = container.GetInstance<IMyPageViewModel>();

然后让它解决它的依赖关系,但是重要的对象是在运行时设置的东西。我无法将其注册为依赖项:

public MyPageViewModel(IDialogManager dialogManager,IPageDisplay pageDisplay, IViewModelProvider viewModelProvider, IContainer container)
{
    this.dialogManager = dialogManager;
    this.pageDisplay = pageDisplay;
    this.viewModelProvider = viewModelProvider;

    //however, here I have no access to the important object that I previously passed in my constructor
    importantObject.DoThatImportantThing(); //obviously error
}

我想也许我应该创建使用&#39; new&#39;并传递IoC容器:

IMyPageViewModel myPageViewModel = new MyPageViewModel(importantObject, container)

然后让它解决它在构造函数中的依赖关系:

public MyPageViewModel(ImportantObject importantObject, IContainer container)
{
    this.dialogManager = container.GetInstance<IDialogManager>();
    this.pageDisplay = container.GetInstance<IPageDisplay>();
    this.viewModelProvider = container.GetInstance<IViewModelProvider>();

    importantObject.DoThatImportantThing();
}

但这让我觉得不是一个好主意,具体来说,我不能用测试寄存器来运行它并让它创建一个虚拟/存根&#34; MyPageViewModel&#34;用于单元测试。

我能想到的另一件事是从构造函数中删除所有逻辑并将其放在初始化方法或属性设置器中。但是,这意味着我必须确保在使用前始终调用initialize,它将隐藏错误/问题。

这些选项中的任何一个是否合理,我应如何管理在依赖注入的构造函数中传递运行时依赖对象?

我试图偏离静态工厂,因为我已经读过很多关于他们的反模式/不良做法。

编辑:为了回应Bruno Garcia的回答,我决定使用一个工厂类型模式来保存容器,并处理对象创建,如下所示:

class PageProvider : IPageProvider
{
    public MyPageViewModel GetMyPage(ImportantObject importantObject)
    {
        //might just get, if it's a single only instance
        return MyPageViewModel(ImportantObject importantObject,
                               container.GetInstance<IDialogManager>(),
                               container.GetInstance<IPageDisplay>(),
                               container.GetInstance<IViewModelProvider>())
    }
}

1 个答案:

答案 0 :(得分:0)

要解决的StructureMap supports passing arguments。这可以帮助您将Factory传递给您正在解析的服务。

值得注意的是,如果你把容器放在身边,事情就会变得非常麻烦。避免将其用作Service Locator

理想情况下,您可以使用容器来解析入口点(例如:Controller,Consumer worker),从那时起,就不再直接使用容器了。如果你需要控制你在构造函数中使用的依赖项的生命周期,有很多方法可以解决这个问题: 采用Func<>或{{1}}。

我建议你仔细阅读你想要用来理解谁控制对象生命周期的文档(如果一个组件实现了IDisposable,谁将要处置它?)。何时创建/处置了生命周期范围?

IoC Container很棒但是如果你不仔细了解终身所有权的概念,很容易发现自己在排除内存泄漏方面的麻烦。