2012-10-11 14 views
10

que tienen una interfaz:fijaciones ninject para una implementación despachador de una interfaz

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

me gustaría configurar Ninject (v3) fijaciones para que pueda tener un método shuffle "despachador" llama a múltiples casos de IService, así:

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 ataduras, que se parecen a esto, terminan lanzar una excepción en 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>(); 

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

+0

¿Por qué necesita 'WhenInjectedExactlyInto', ¿por qué no' To'? – casperOne

+0

Porque 'WhenInjectedExactlyInto' impide que 'SomeOtherService' y' YetAnotherService' se inyecten en cualquier cosa que no sea 'DispatcherService'. He utilizado un enfoque similar para "ajustar" (ver http://stackoverflow.com/questions/6752674/dependency-injection-how-to-configure-interface-bindings-for-wrapping), pero estoy tratando de hacer que funcione para el caso de inyección múltiple. – FMM

+0

¿Ha mirado las diversas extensiones de Event Broker? Todas hacen lo que sus ejemplos hacen en gran profundidad. OK, dijiste que era solo un ejemplo, ¡estaré callado! –

Respuesta

2

Si el despachador es el única IService que se va a tomar una lista de iServices como un parámetro, esto hace el trabajo (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 de que When cláusula funciona para este caso es que el campo IsUnique de IRequest se establece en true cuando su constructor solicita una instancia única de un servicio. Como su DispatcherService requiere un IEnumerable, el valor es false al activar DispatcherService. Eso evita que la dependencia circular ocurra.

Realmente, 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 cortocircuitando su dependencia circular parece ser esta:

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

¡Gracias, buen señor! Si puede actualizar su respuesta para incluir cierta información en la bandera 'IsUnique' de' IRequest', la respuesta y la recompensa van para usted. – FMM

+0

@FMM Gracias. Espero que mi explicación no sea demasiado torpe :) –

+0

¡Excelente, gracias! La instancia de instancia única frente a instancia múltiple no es inmediatamente evidente a partir del nombre 'IsUnique', en mi humilde opinión. – FMM

1

he de reconocer que no soy tan familiarizados con la API de Ninject, pero creo que esto haría el truco:

kernel.Bind<IService>().To<DispatcherService>(); 

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

No funciona. Todavía causa una dependencia cíclica. Usar 'IService []' en lugar de 'IEnumerable ' tampoco tiene impacto. – FMM

+0

Lo siento. Creo que entiendo por qué (pero no estoy seguro de cómo resolver esto en Ninject). Ninject permite múltiples llamadas a 'Bind ()' con diferentes implementaciones, y Ninject las usará todas para resolver la colección.(Esta es una característica que tienen la mayoría de los contenedores y es algo que no me gusta mucho). Creo que esto anula el registro manual de 'IEnumerable '. Creo que el truco es registrar un 'IList ' o 'IService []' y dejar que su 'DispatcherService' dependa directamente de este' IList 'o' IService [] '. – Steven

0

Usted podría separar los dos subconjuntos (ya sea despachador o los Receptores) de la forma de hacer una de ellas es una vinculación con nombre, y luego usar el nombre como una forma de alimentar una a la otra (NamedAttribute o en su cableado)

+0

¿Ejemplo de código? También parece que el constructor 'DispatcherService' necesitaría atributos específicos de Ninject, que me gustaría evitar. – FMM

+0

Lo sentimos, estamos muy ocupados en este momento, hacemos ping nuevamente si no puedes ordenarlo sin un ejemplo. Echa un vistazo a la wiki para ver ejemplos de enlaces nombrados ... –

1

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

Cuestiones relacionadas