简体   繁体   中英

Passing constructor parameters when resolving types in Unity: Best practice

It's sometimes necessary when using dependency injection to provide the parameters to use in the constructor. This is something that's supported in Unity (and other dependency injection containers), so that when it tries to create an instance of the type, it can provide your arguments as parameters in the constructor.

My question is: is this approach desirable?

Within an interface it is not possible to specify which parameters an implementing class must have. By specifying the parameters to Unity, you are assuming that the implementing class has these parameters, and you are placing implicit constraints over future implementing classes. These constraints cannot be communicated through the interface.

So, is this is flaw in how interfaces themselves are specified (in .NET), eg. should it be possible to specify constructor signatures? Or has this feature (of being able to provide constructor parameters) been included in Unity due to some other need?

The only real workable approach (to me) seems to be use a factory to create the implementing classes, and do dependency injection on the factory.

I appreciate my question here might not be clear, so I'll ask it slightly differently: what's the best way to do dependency injection on a class which has a constructor requiring parameters?

(I do not believe this question to be subjective, as there should probably be a single design pattern for this type of dependency injection.)

EDIT:

I should add, that my main problem is that I may create a new implementing class which has additional constructor parameters (where the constructor parameters are not things that can be created by unity).

I'm not sure where you got the idea that constructor injection does not fit with DI. I'd say that the real situation is the opposite of that: constructor injection is one of the most common patterns utilised to achieve dependency injection - I'd go as far as saying that it is the most common pattern, and that view is certainly backed up by the fact that that majority of Inversion of Control containers (DI containers) use constructor injection as their preferred mechanism.

StructureMap for example has a core, very specific support for constructor injection where it will pick the constructor with the most parameters as the constructor used for dependency resolution.

What you are saying by using the constructor injection pattern is that "I am removing the hard coded dependencies within my class by specifying them as parameters passed into the constructor - my class cannot be instantiated without these dependencies". Of course, the first half of that statement is the essence of DI, but the second half enforces this more.

Dependencies are an implementation detail that should be able to be changed easily, providing a flexible, loosely coupled solution. They are about the how, not the what. Interfaces specify the what. So I'd say that your suggestion of specifying dependencies in interfaces actually goes against the concept of dependency injection.

And as far as your statement about factories - this is exactly what IOC containers are - great big factories that take care of a solution's dependency tree, so you don't need to care.

Edit

I think maybe you are asking about the case where you want to provide a non-dependency constructor parameter, such as an id for a referenced entity, or an initial state enum?

I personally don't see a problem with an IOC container allowing for this. It is still initial state of your class and hence the rules for the creation of that state need to be explicitly expressed. It can mean that you sometimes need more references to your IOC container that you might like, but it is not a horrible enough situation to abandon the other benefits of counstructor injection.

The responsibility of IoC containers (say Unity) is to connect interfaces with concrete implementations. That means your container must know the interface and how to create the object that implements the interface. Using constructor injection is perfectly legal and the recommended way. Unity will create the concrete implementation when your application requests an interface through the Resolve() method. The Unity container itself is the factory that creates your objects, you use Unity because you don't want to implement those factories by yourself.

The issue here is the definition of the InjectionConstructor in Unity vs say the one in Castle.Windsor.

In Unity, if you need to inject a particular parameter, say an AppSetting you are also forced to supply all the other parameters thus fixing the signature of the constructor. However, in Castle.Windsor it takes the parameter you've supplied and then uses the resolution mechanism to locate the other paramaters in the normal way.

It would be possible to introduce this into Unity by writing a custom Builder strategy that did a "best-fit" approach to which constructor to use rather than the default greedy/supply everything which is the default.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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