1
votes

I'm looking at contextual binding with Ninject. This is for when you have multiple implementations of some abstraction, and context in the injection target class determines which of those implementations is injected.

In the documentation, the example using "named bindings" looks like this:

Bind<IWeapon>().To<Shuriken>().Named("Strong");
Bind<IWeapon>().To<Dagger>().Named("Weak");

class WeakAttack {
    readonly IWeapon _weapon;
    public WeakAttack([Named("Weak")] IWeapon weakWeapon){
        _weapon = weakWeapon;
    }
    public void Attack(string victim){
        Console.WriteLine(_weapon.Hit(victim));
    }
}

That means that the assembly which contains WeakAttack will obviously have to reference Ninject to use the NamedAttribute in the constructor. The target of dependency injection should not have to know which DI container is used. What am I missing here?

1

1 Answers

3
votes

One way to do this is with custom attributes defined in the target assembly:

public class BirdAttribute : Attribute { }
public class MonkeyAttribute : Attribute { }
public interface IAnimal { }
public class Bird : IAnimal { }
public class Monkey : IAnimal { }

Use the custom attributes on the constructor arguments, e.g.:

public class BirdCage
{
    public BirdCage([Bird]IAnimal bird) => Bird = bird;
    public IAnimal Bird { get; }
}

public class Zoo
{
    public Zoo([Monkey]IAnimal monkey, [Bird]IAnimal bird)
    {
        Monkey = monkey;
        Bird = bird;
    }

    public IAnimal Monkey { get; }
    public IAnimal Bird { get; }
}

And the bindings will use WhenTargetHas, like so:

internal class Module : NinjectModule
{
    public override void Load()
    {
        Bind<IAnimal>().To<Bird>().WhenTargetHas<BirdAttribute>();
        Bind<IAnimal>().To<Monkey>().WhenTargetHas<MonkeyAttribute>();
    }
}

This maintains the proper direction of inversion of control because the assembly with the Ninject bindings knows about the target (i.e. the custom attributes), but the target doesn't have to know which IoC container is being used.