Используя 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"))
но это большой фуги, если вы спросите меня....