简体   繁体   English

IOC容器的最佳实践

[英]Best Practices for IOC Container

I'm using the Unity IOC container and I'm just wondering what is the best best way to access the container for multiple classes. 我正在使用Unity IOC容器,我只是想知道访问多个类的容器的最佳方法是什么。

Should every class have an IUnityContainer member and then pass the container in by constructor? 每个类都应该有一个IUnityContainer成员,然后通过构造函数传递容器吗? Should there be a singleton class with an IOC container? 是否应该有一个带有IOC容器的单例类?

How about asp.net development? asp.net开发怎么样?

Could somebody guide me in the right direction? 有人可以指导我朝正确的方向发展吗? Thanks. 谢谢。

IMHO it is not advisable to inject the entire container into a class or to have an application wide static IoC service locator. 恕我直言,不建议将整个容器注入类或具有应用程序范围的静态IoC服务定位器。

You want to be able to see from the constructor of a class (lets call it Foo), what kind of services/objects it is using to get the work done. 您希望能够从类的构造函数中看到(让我们称之为Foo),它使用什么样的服务/对象来完成工作。 This improves clarity, testability and degubability. 这提高了透明度,可测试性和可脱气性。

Lets say Foo only needs the email service, but I pass in the whole container and somewhere in the code the email service gets resolved from the container. 让我们说Foo只需要电子邮件服务,但我传入整个容器和代码中的某个地方,电子邮件服务从容器中解析出来。 In this case it will be very hard to follow. 在这种情况下,将很难遵循。 Instead it is better to inject the email service directly to state Foo's dependencies clearer. 相反,最好将电子邮件服务直接注入状态Foo的依赖关系更清晰。

If Foo needs to create multiple instances of the email service, it is better to create and inject an EmailServiceFactory (via the IoC container), which will create the required instances on the fly. 如果Foo需要创建电子邮件服务的多个实例,最好创建并注入一个EmailServiceFactory(通过IoC容器),它将动态创建所需的实例。

In the latter case, Foo's dependencies are still indicated as specific as possible - only the ones, that the EmailServiceFactory can create. 在后一种情况下,Foo的依赖关系仍然表示尽可能具体 - 只有EmailServiceFactory可以创建的依赖关系。 Had I injected the whole container, it would not be clear what services provided by it are Foo's exact dependencies. 如果我注入了整个容器,那就不清楚它提供的服务是Foo的确切依赖。

Now, if I later want to provide different instances of the email service, I swap it out inside the EmailServiceFactory. 现在,如果我以后想要提供电子邮件服务的不同实例,我会在EmailServiceFactory中交换它。 I could swap out the whole factory as well, if all the services it creates need to be swapped (eg during testing). 如果它所创建的所有服务都需要交换(例如在测试期间),我也可以换掉整个工厂。

So at the cost of creating one extra class (the factory), I get much cleaner code and won't have to worry about curious bugs that may occur when global statics are used. 因此,以创建一个额外的类(工厂)为代价,我获得了更清晰的代码,并且不必担心使用全局静态时可能发生的奇怪错误。 Additionally when supplying mocks for testing, I know exactly what mocks it needs and don't have to mock out an entire container's types. 另外,当提供模拟测试时,我确切地知道它需要什么模拟,而不必模拟整个容器的类型。

This approach also has the advantage, that now, when a module is initialized (only applies to Prism / Modularity), it doesn't have to register all of the types of objects it supplies with the IoC container. 这种方法也具有优势,现在,当模块初始化时(仅适用于Prism / Modularity),它不必注册它提供给IoC容器的所有类型的对象。 Instead it can just register its ServiceFactory which then supplies those objects. 相反,它只能注册其ServiceFactory然后提供这些对象。

To be clear, the module's initialization class (implements IModule) should still receive the application wide IoC container in its constructor in order to supply services, that are consumed by other modules, but the container should not invade into the module's classes. 为了清楚起见,模块的初始化类(实现IModule)仍应在其构造函数中接收应用程序范围的IoC容器,以便提供其他模块使用的服务,但容器不应侵入模块的类。

Finally, what we have here is another fine example of how an extra layer of indirection solves a problem. 最后,我们这里有一个额外的间接层如何解决问题的另一个很好的例子。

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

you can register the container in itself and have it injected like every other dependency property, like so: 你可以在容器中注册容器并像其他依赖属性一样注入容器,如下所示:

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

classes that need to access it will have the following property: 需要访问它的类将具有以下属性:

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

thus, the container is injected whenever an instance of such a class is resolved/built up. 因此,只要解决/建立了这种类的实例,就注入容器。

This is more flexible as it works for multiple containers within the same application, which would not be possible with the singleton pattern. 这更灵活,因为它适用于同一应用程序中的多个容器,而使用单例模式是不可能的。

If all of your objects need a reference to the container then you should look into reworking the code some. 如果所有对象都需要对容器的引用,那么您应该考虑重新编写代码。 While still preferable to calling new everywhere it still scatters the responsibility of building your object graphs throughout your code. 虽然仍然比在任何地方调用new更好,但它仍然分散了在整个代码中构建对象图的责任。 With that kind of usage it strikes me as being used more like a ServiceLocator instead of a IoC Container. 有了这种用法,它更像是一个ServiceLocator而不是IoC Container。

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

I have a post on this subject at my blog where I´m using something along the lines of t3mujin answer. 我在我的博客上有一篇关于这个主题的帖子,我使用了t3mujin答案的内容。 Feel free to use it (don´t bother that it´s sharepoint related...that doesn´t matter): 随意使用它(不要打扰它的相关点...无关紧要):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM