Связывание Ninject для реализации диспетчера интерфейса
У меня есть интерфейс:
public interface IService
{
void DoStuff(int parm1, string parm2, Guid gimmeABreakItsAnExampleK);
}
Я хотел бы настроить привязки Ninject (v3), чтобы у меня мог быть метод shuffle "dispatcher", вызывающий несколько экземпляров IService
, например:
public sealed class DispatcherService : IService
{
private IEnumerable<IService> _children;
public DispatcherService(IEnumerable<IService> children)
{
this._children = children.ToList();
}
public void DoStuff(int parm1, string parm2, Guid gimmeABreakItsAnExampleK)
{
foreach(var child in this._children)
{
child.DoStuff(parm1, parm2, gimmeABreakItsAnExampleK);
}
}
}
Однако мои привязки, которые выглядят так, завершают выдачу исключения во время выполнения, указывающее циклическую зависимость:
this.Bind<IService>().To<DispatcherService>();
this.Bind<IService>().To<SomeOtherService>()
.WhenInjectedExactlyInto<DispatcherService>();
this.Bind<IService>().To<YetAnotherService>()
.WhenInjectedExactlyInto<DispatcherService>();
Возможно ли это? Если да, то что я делаю неправильно? Может ли ниндзя избежать этой циклической гибели зависимости?
Ответы
Ответ 1
Если ваш диспетчер является единственным IService, который будет принимать список IServices в качестве параметра, это работает (я тестировал):
kernel.Bind<IService>().To<DispatcherService>().When(x => x.IsUnique);
this.Bind<IService>().To<SomeOtherService>()
.WhenInjectedExactlyInto<DispatcherService>();
this.Bind<IService>().To<YetAnotherService>()
.WhenInjectedExactlyInto<DispatcherService>();
Причина, по которой это предложение When
работает для этого случая, заключается в том, что поле IsUnique
IRequest
устанавливается в true
, когда ваш конструктор вызывает один экземпляр службы. Поскольку ваш DispatcherService
вызывает IEnumerable
, при DispatcherService
значение false
. Это предотвращает появление циклической зависимости.
Действительно, любой правильный способ сказать ядру не пытаться внедрить DispatcherService в себя будет работать (это просто потенциально полезный пример).
Изменить: более явный способ просто короткого замыкания вашей циклической зависимости выглядит следующим образом:
kernel.Bind<IService>().To<DispatcherService>().When(
request => request.Target.Member.DeclaringType != typeof (DispatcherService));
Ответ 2
Я должен признать, что я не знаком с API Ninject, но я думаю, что это сделало бы трюк:
kernel.Bind<IService>().To<DispatcherService>();
kernel.Bind<IEnumerable<IService>>().ToMethod(() => new IService[]
{
kernel.Get<SomeOtherService>(),
kernel.Get<YetAnotherService>(),
});
Ответ 3
Почему бы не избавиться от IService в DispatcherService и назвать его IDispatcherService и заставить вызываемые службы (приемники) реализовать IService?
Ответ 4
Вы можете отделить два подмножества (либо Диспетчер, либо ресиверы) от пути, сделав одно из них Именованным Связыванием, а затем используйте это имя как способ подачи одного к другому (либо через NamedAttribute
или в вашей проводке)