问题
Example solution to demonstrate the problem:
class World
{
public override string ToString()
{
return "Hello World";
}
}
class Hello
{
[Inject]
public World theWorld { get; set; }
public Hello(IKernel kernel)
{
kernel.Inject(this);
}
public override string ToString()
{
return theWorld.ToString();
}
}
class Program
{
static IKernel kernel = new StandardKernel();
static void RegisterServices()
{
kernel.Bind<World>().ToSelf();
}
static void Main(string[] args)
{
RegisterServices();
Hello hello = new Hello(kernel);
Console.WriteLine(hello.ToString());
Console.ReadLine();
}
}
This is the way I got property injection actually working.
It won`t work if:
- Property is not public (or its setter).
- The class that asks for injection doesnt get IKernel instance, to call
kernel.Inject(this);
.
For me its seems very excess and wrong to do this only to get instance of a property. Are there simpler ways or I haven't considered something?
回答1:
Property injection is typically bad since it causes Temporal Coupling. Property injection should only be used for dependencies that are truly optional (which it isn't in your case). Dependencies, however, should hardly ever be optional. Even in case there is no implementation for a dependency, it's better to create and inject a Null Object implementation than injecting a null
reference. Instead of using Property Injection, prefer injecting all required dependencies through the constructor.
Another bad practice is letting your application code take a dependency on the container itself (or an abstraction that represents the resolve-API of the container). This is an anti-pattern called Service Locator. The only place you should reference the container is in your Composition Root. The Program
class in your example represents the Composition Root.
Instead your Hello
class should simply accept World
as required constructor argument:
class Hello
{
private readonly World theWorld;
public Hello(World theWorld)
{
this.theWorld = theWorld ?? throw new ArgumentNullException("theWorld");
}
public override string ToString()
{
return this.theWorld.ToString();
}
}
Notice how I completely removed any reference to the container from this class. This makes the class simpler, more maintainable, more testable, and even makes it possible to compose this class without using a DI container tool; a practice commonly known as Pure DI. When your application is small, Pure DI can be a better option than using a container.
Here's how your Program
class can look like:
class Program
{
static void Main(string[] args)
{
// Configure
var kernel = new StandardKernel();
kernel.Bind<Hello>().ToSelf();
kernel.Bind<World>().ToSelf();
// Resolve
var hello = kernel.Get<Hello>();
// Use
Console.WriteLine(hello.ToString());
Console.ReadLine();
}
}
Without a container, it would be as follows:
class Program
{
static void Main(string[] args)
{
// Resolve
var hello = new Hello(new World());
// Use
Console.WriteLine(hello.ToString());
Console.ReadLine();
}
}
来源:https://stackoverflow.com/questions/39580951/is-property-injection-considered-to-be-bad