IOC容器的最佳实践

时间:2009-01-26 16:02:33

标签: c# inversion-of-control unity-container

我正在使用Unity IOC容器,我只是想知道访问多个类的容器的最佳方法是什么。

每个类都应该有一个IUnityContainer成员,然后通过构造函数传递容器吗?是否应该有一个带有IOC容器的单例类?

asp.net开发怎么样?

有人可以指导我朝正确的方向发展吗?谢谢。

6 个答案:

答案 0 :(得分:21)

恕我直言,不建议将整个容器注入类或具有应用程序范围的静态IoC服务定位器。

您希望能够从类的构造函数中看到(让我们称之为Foo),它使用什么样的服务/对象来完成工作。这提高了透明度,可测试性和可脱气性。

让我们说Foo只需要电子邮件服务,但我传入整个容器,并在代码中的某个地方通过容器解析电子邮件服务。在这种情况下,将很难遵循。相反,最好将电子邮件服务直接注入状态Foo的依赖关系更清楚。

如果Foo需要创建电子邮件服务的多个实例,最好创建并注入一个EmailServiceFactory(通过IoC容器),它将动态创建所需的实例。

在后一种情况下,Foo的依赖关系仍然尽可能具体 - 只有EmailServiceFactory可以创建的依赖关系。如果我注入了整个容器,那么它提供的服务是否与Foo的确切依赖关系并不清楚。

现在,如果我以后想要提供不同的电子邮件服务实例,我会在EmailServiceFactory中交换它。如果它所创建的所有服务都需要交换(例如在测试期间),我也可以换掉整个工厂。

因此,以创建一个额外的类(工厂)为代价,我得到了更清晰的代码,并且不必担心使用全局静态时可能发生的奇怪错误。另外,在提供测试的模拟时,我确切地知道它需要什么模拟,而不必模拟整个容器的类型。

这种方法也有优势,现在,当模块初始化(仅适用于Prism / Modularity)时,它不必注册它提供给IoC容器的所有类型的对象。相反,它只需注册其ServiceFactory然后提供这些对象。

要明确的是,模块的初始化类(实现IModule)仍然应该在其构造函数中接收应用程序范围的IoC容器,以便提供其他模块使用的服务,但容器不应该侵入模块的类。

最后,我们在这里有一个额外的间接层如何解决问题的另一个很好的例子。

答案 1 :(得分:13)

将IOC容器放在流程的最高级别/入口点,并使用它将依赖项注入其下的所有内容。

答案 2 :(得分:6)

你可以在容器中注册容器并像其他依赖属性一样注入容器,如下所示:

IUnityContainer container = new UnityContainer();
container.RegisterInstance<IUnityContainer>(container);

需要访问它的类将具有以下属性:

private IUnityContainer unityContainer;
[Dependency]
public IUnityContainer UnityContainer
{
    get { return unityContainer; }
    set { unityContainer = value; }
}

因此,只要解析/建立了这样一个类的实例,就会注入容器。

这更灵活,因为它适用于同一个应用程序中的多个容器,而使用单例模式是不可能的。

答案 3 :(得分:2)

如果您的所有对象都需要对容器的引用,那么您应该考虑重新编写代码。虽然仍然比在任何地方调用new更好,但它仍然分散了在整个代码中构建对象图的责任。有了这种用法,它更像是一个ServiceLocator,而不是IoC容器。

答案 4 :(得分:0)

另一种选择是使用CommonServiceLocator,虽然它可能是无意义的间接,但您可以使用ServiceLocator.Current作为所有类已知的实例

答案 5 :(得分:0)

我在我的博客上有一篇关于这个主题的帖子,我在使用t3mujin的回答。随意使用它(不要打扰它与分享点相关......这无关紧要):

http://johanleino.spaces.live.com/blog/cns!6BE273C70C45B5D1!213.entry