Как избежать необходимости ссылки на Ninject в целевой сборке инъекции при использовании контекстной привязки

Я рассматриваю контекстную привязку с помощью Ninject. Это на тот случай, если у вас есть несколько реализаций некоторой абстракции, и контекст в целевом классе внедрения определяет, какая из этих реализаций внедряется.

В документации пример с использованием «именованных привязок» выглядит так:

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));
    }
}

Это означает, что сборка, содержащая WeakAttack, очевидно, должна будет ссылаться на Ninject, чтобы использовать NamedAttribute в конструкторе. Цель внедрения зависимостей не должна знать, какой контейнер внедрения зависимостей используется. Что мне здесь не хватает?


person rory.ap    schedule 11.06.2019    source источник


Ответы (1)


Один из способов сделать это — использовать настраиваемые атрибуты, определенные в целевой сборке:

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

Используйте настраиваемые атрибуты в аргументах конструктора, например:

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; }
}

И привязки будут использовать WhenTargetHas, например:

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

Это поддерживает правильное направление инверсии управления, поскольку сборка с привязками Ninject знает о цели (т. е. настраиваемых атрибутах), но цель не должна знать, какой контейнер IoC используется.

person rory.ap    schedule 11.06.2019