una tipos que puede programacion interfaz interfaces instancia implementacion declaracion declara cómo crear caracteristicas atributos c# .net dependency-injection ninject ioc-container

c# - tipos - que es una interfaz en programacion



Enlaces Ninject para una implementación del despachador de una interfaz (4)

Tengo una interfaz:

public interface IService { void DoStuff(int parm1, string parm2, Guid gimmeABreakItsAnExampleK); }

Me gustaría configurar enlaces de Ninject (v3) para que pueda hacer que un método aleatorio "dispatcher" llame a varias instancias de IService , de esta forma:

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

Sin embargo, mis enlaces, que se ven así, terminan arrojando una excepción en el tiempo de ejecución que indica una dependencia cíclica:

this.Bind<IService>().To<DispatcherService>(); this.Bind<IService>().To<SomeOtherService>() .WhenInjectedExactlyInto<DispatcherService>(); this.Bind<IService>().To<YetAnotherService>() .WhenInjectedExactlyInto<DispatcherService>();

es posible? Si es así, ¿qué estoy haciendo mal? ¿Pueden los ninja escapar de esta condena a la dependencia cíclica?


¿Por qué no deshacerse de IService en el DispatcherService y llamarlo IDispatcherService y hacer que los servicios llamados (receptores) implementen IService?


Debo admitir que no estoy tan familiarizado con la API de Ninject, pero creo que esto sería el truco:

kernel.Bind<IService>().To<DispatcherService>(); kernel.Bind<IEnumerable<IService>>().ToMethod(() => new IService[] { kernel.Get<SomeOtherService>(), kernel.Get<YetAnotherService>(), });


Puede segregar los dos subconjuntos (ya sea Dispatcher o los receptores) haciendo que uno de ellos sea un NamedAttribute nombre, y luego usar el nombre como una forma de alimentar el uno al otro (ya sea a través de una NamedAttribute o en su cableado)


Si su despachador es el único IService que tomará una lista de IServices como parámetro, esto funciona (lo he probado):

kernel.Bind<IService>().To<DispatcherService>().When(x => x.IsUnique); this.Bind<IService>().To<SomeOtherService>() .WhenInjectedExactlyInto<DispatcherService>(); this.Bind<IService>().To<YetAnotherService>() .WhenInjectedExactlyInto<DispatcherService>();

La razón por la que la cláusula When funciona para este caso es porque el campo IsUnique de IRequest se establece en true cuando el constructor solicita una instancia única de un servicio. Como su DispatcherService llama a un IEnumerable , el valor es false cuando se activa el DispatcherService . Eso evita que la dependencia circular ocurra.

En realidad, cualquier forma correcta de decirle al kernel que no intente inyectar el DispatcherService en sí mismo funcionaría (este es solo un ejemplo potencialmente útil).

Editar: La forma más explícita de simplemente cortocircuitar tu dependencia circular parece ser esta:

kernel.Bind<IService>().To<DispatcherService>().When( request => request.Target.Member.DeclaringType != typeof (DispatcherService));