Best Practices for IOC Container

2019-01-21 17:22发布

问题:

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.

Should every class have an IUnityContainer member and then pass the container in by constructor? Should there be a singleton class with an IOC container?

How about asp.net development?

Could somebody guide me in the right direction? Thanks.

回答1:

IMHO it is not advisable to inject the entire container into a class or to have an application wide static IoC service locator.

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. 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. 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.

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.

In the latter case, Foo's dependencies are still indicated as specific as possible - only the ones, that the EmailServiceFactory can create. Had I injected the whole container, it would not be clear what services provided by it are Foo's exact dependencies.

Now, if I later want to provide different instances of the email service, I swap it out inside the EmailServiceFactory. I could swap out the whole factory as well, if all the services it creates need to be swapped (e.g. 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. Instead it can just register its ServiceFactory which then supplies those objects.

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.

Finally, what we have here is another fine example of how an extra layer of indirection solves a problem.



回答2:

Put the IOC container at the highest level / entry point in the process and use it to inject dependencies in everything underneath it.



回答3:

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.



回答4:

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. With that kind of usage it strikes me as being used more like a ServiceLocator instead of a IoC Container.



回答5:

Another option would be using the CommonServiceLocator, although it may be a pointless indirection, you may use the ServiceLocator.Current as the instance known by all classes



回答6:

I have a post on this subject at my blog where I´m using something along the lines of t3mujin answer. 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