Используя Ninject, могу ли я создать экземпляр из интерфейса, не подвергая себя конкретному классу?

Образцы, которые я видел до сих пор, выглядят следующим образом:

Напишите свой код следующим образом:

public class Samurai {
  public IWeapon Weapon { get; private set; }
  public Samurai(IWeapon weapon) {
    Weapon = weapon;
  }
}

И Ninject может сопоставить интерфейс с конкретным типом, подобным этому...

public class WarriorModule : NinjectModule {
  public override void Load() {
    Bind<IWeapon>().To<Sword>();
  }
}

Итак, когда я говорю var samurai = kernel.Get<Samurai>(); в моем объекте самурая, мой IWeapon автоматически является Мечом.

Это круто, но что, если я хочу, чтобы только ISword без самурая и конкретного меча был помечен как внутренний?

В настоящее время я использую домашний преобразователь зависимостей, где я мог бы сказать var sword = DependencyResolver.Current.Resolve<ISword>();, и он возвращает мне бросок меча как ISword. Мои конкретные классы отмечены как внутренние, поэтому разработчик должен пройти через свой преобразователь зависимости, чтобы создать экземпляр. Есть ли у Ninject что-то подобное?

И вопрос бонуса, я украшаю свои интерфейсы специальным атрибутом DefaultConcreteType, который может использовать мой зависимый преобразователь, если отображение не существует. Есть ли у Ninject что-нибудь подобное?

Спасибо

Ответ 1

Когда вы привязываете интерфейс к конкретному типу, вы можете запросить экземпляр этого интерфейса и получить конкретный тип. В вашем примере вы можете сделать это:

var sword = kernel.Get<ISword>();

И это даст вам конкретный объект Sword. Вы также можете сделать многое с системой привязки. Вы даже можете Bind<ISword>().ToMethod(MySwordFactory); и написать метод для получения Мечей на основе запрашивающего контекста.

Еще одна вещь, которую вы можете сделать, - это изменить способ привязки, основанный на типе, в который он вводится. Например, вы можете открыть свойство в пользовательском классе следующим образом:

public class MyClass {
    [Inject]
    public ISword Sword { get; set; }
}

И тогда вы можете привязываться к конкретной реализации ISword на основе MyClass:

Bind<ISword>().To<Sword>().WhenInjectedInto<MyClass>();

Есть намного больше вариантов, но это должно дать вам общий обзор.

Ответ 2

Я бы рекомендовал использовать абстрактный factory, который может создать ISword s. Это имеет преимущество перед DependencyResolver в том, что типы, которые он может создать, ограничены (до ISword).

Ваш абстрактный factory/должен быть общедоступным, как и ваш DependencyResolver.

Ответ 3

Это не отвечает на ваш вопрос напрямую, но я знаю, что с Unity вы можете сделать это, используя файлы Config, а не проводку своих зависимостей в коде. Ninject, к сожалению, не поддерживает файлы Config.

Ваша альтернатива этому - использовать неосновные перегрузки:

Bind(typeof(IWeapon)).To(typeof(Sword));

И тогда вы сможете сделать что-то вроде:

Bind(typeof(IWeapon)).To(Type.GetType("MyNamespace.MyInternalSword"))

но это большой фуги, если вы спросите меня....