问题
I've a class which have a constructor like this:
private string _someString;
private ObjectA _objectA;
private ObjectB _objectB;
private Dictionary<Enum, long?> _dictionaryA;
private Dictionary<Tuple<Enum,long?>, long?> _dictionaryB;
public SomeDiClass(string someString)
{
_someString = someString;
_objectA = new ObjectA();
_objectB = new ObjectB();
_dictionaryA = new Dictionary<Enum, long?>();
_dictionaryB = new Dictionary<Tuple<Enum, long?>, long?>();
}
I want to get the dependency creation out of this constructor. In a first step I would move the ObjectA and B dependency to the constructors parameters to inject them via constructor injection. I would like to use a IoC container for this purpose, that's where I stuck at the moment. The question is what to to with someString and the dictionaries. I need to inject them to the class, because the content of the dictionaries will be an important part of unit tests. Would it be a good idea to inject the string and the dictionaries via property injection (I don't need them in other classes), so I would end up with something like this?:
private ObjectA _objectA;
private ObjectB _objectB;
public string SomeString { get; set; }
public Dictionary<Enum, long?> DictionaryA { get; set; }
public Dictionary<Tuple<Enum, long?>, long?> DictionaryB { get; set; }
public SomeDiClass(ObjectA objectA, ObjectB objectB)
{
_objectA = objectA;
_objectB = objectB;
}
Is there a best practice to solve something like this?
回答1:
Dependency Injection is not a goal, but a solution to a particular set of problems. For instance, Dependency Injection makes it easy to replace abstractions for unit testing and makes your application more flexible, since you can swap, decorate and intercept dependencies without the consuming class knowing.
That doesn't mean that you should inject every dependency a class has, since it must help you in making the class more testable and the system more maintainable. So you have to ask yourself whether it helps from a testing perspective to inject those dictionaries from the outside or if it helps to make your application more flexible.
This last question is hard to answer for me, since your question doesn't have enough detail. But here are some pointers:
The only things you typically want to inject into a class are services and configuration values.
A service is some contract/abstraction/interface that provides 'a service'. This typically means that the service will do something on your behalf, such as calculate prices, communicate to the database, cache values, return the system's time, format your hard drive :)
A configuration value is what it is; just a value. But you need to inject it, since it can't be hard coded into the class, and you don't want the class to fetch the value itself from the ConfigurationManager
for instance, since that would create a hidden dependency (on the Configurationmanager
) and this would make the class harder to test.
Other things, such as primitives, messages, DTOs, collection types and entities, and anything else that doesn't provide any service (business logic) and isn't in the way of unit testing, doesn't have to be abstracted and therefore doesn't have to be injected. In your case the dictionaries some part of the internal state of the SomeDiClass
class, not a service your class depends on.
If on the other hand, those dictionaries are reused by other services, those dictionaries will have to be injected. But you never want to inject such dictionary itself directly, since the dictionary itself is no service. Instead you need to create an abstraction around them; something that hides the details of that dictionary and provides the application with a service around it.
回答2:
You should use property injection (or setter injection) when object creation of your type is out of your control. Like aspx Page, HttpHandler, ApiController etc. For all others situations it is recommended to use constructor injection.
To resolve dependencies for aspx Page using StructureMap, i use the following approach.
First, I create a BasePage class and use StructureMap's BuildUp() method in the constructor to resolve dependencies of the derived pages. Code is given below:
public class BasePage : Page
{
public BasePage()
{
// instruct StructureMap to resolve dependencies
ObjectFactory.BuildUp(this);
}
}
public class Default : BasePage
{
public ICustomerService customerService { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
// can start using customerService
}
}
public class Login : BasePage
{
public IAuthenticationService authenticationService { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
// can start using authenticationService
}
}
来源:https://stackoverflow.com/questions/18779894/dependency-injection-when-to-use-property-injection