alex kostin alex kostin - 2 months ago 30
C# Question

Is Ninject property injection considered to be bad?

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:


  1. Property is not public (or its setter).

  2. 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. Is there simpler ways or I havent considered something?

Answer

Property injection is typically bad since it causes Temporal Coupling. Property injection should only be used for dependencies that are truly option (which 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 inject a Null Object implementation than injecting a null reference. All required dependencies should be injected through the constructor.

Another bad practice is letting your application code take a dependency on the container itself. This is an anti-pattern called Service Locator. The only place you should reference the container is in your Composition Root, which is the Program class in your case.

So instead, your Hello class should simply accept World as required constructor argument:

class Hello
{
    private readonly World theWorld;

    public Hello(World theWorld) {
        if (theWorld == null) throw new ArgumentNullException("theWorld");
        this.theWorld = theWorld;
    }

    public override string ToString() {
        return theWorld.ToString();
    }
}

Notice how we completely removed any reference to the container from this class. This makes the class simpler, more maintainable, more testable, and 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();
    }
}