2011-10-31 14 views
8

quiero unir múltiples implementaciones de un servicio y tienen todos ellos llamados a la vez:Ninject multidifusión

var kernel = new StandardKernel(); 

kernel.Bind<IBreakfast>.To<Spam>(); 
kernel.Bind<IBreakfast>.To<Eggs>(); 
kernel.Bind<IBreakfast>.To<MoreSpam>(); 

kernel.Get<IBreakfast>().Eat(); // call Eat method on all three bound implementations 

Ninject no lo hace así, y arrojará una excepción por tener varios enlaces. ¿Hay alguna manera de evitar ese error y llamar a todas las implementaciones?

Además, las llamadas Bind<> pueden realizarse en diferentes proyectos que pueden o no estar cargados en tiempo de ejecución, por lo que no será posible crear una única implementación para llamarlos. Esto es parte de una arquitectura de plug-in para un sitio web ASP.NET MVC 3.

Respuesta

12

Si utiliza la inyección de constructor y tiene un parámetro List<IBreakfast>, Ninject construirá una lista con todas sus vinculaciones. A continuación, puede llamar al Eat en estas instancias.

Puede usar este patrón para hacer que Ninject cree una lista de sus complementos, por ejemplo.

[Test] 
    public void Test() 
    { 
     IKernel kernel = new StandardKernel(); 

     kernel.Bind<IBreakfast>().To<Eggs>(); 
     kernel.Bind<IBreakfast>().To<Spam>(); 
     kernel.Bind<IBreakfast>().To<MoreSpam>(); 

     var bling = kernel.Get<Bling>(); 
    } 

    private class Bling 
    { 
     public Bling(List<IBreakfast> things) 
     { 
      things.ForEach(t => t.Eat()); 
     } 
    } 

    private interface IBreakfast 
    { 
     void Eat(); 
    } 

    private class Ingrediant : IBreakfast 
    { 
     public void Eat(){Console.WriteLine(GetType().Name);} 
    } 

    private class Eggs : Ingrediant{} 
    private class Spam : Ingrediant{} 
    private class MoreSpam : Ingrediant { } 

Salida:

huevos
spam
MoreSpam

+0

voy a tratar esto en la mañana cuando llegue a trabajar, pero no se Ninject generará un error en la segunda llamada a bind <> () .To <>() '? – MikeWyatt

+5

@MikeWyatt: No, múltiples 'Bind's están bien. Lo que no está bien es ir a 'Obtener ' que rinde más que un elemento 'Individual'. Si desea hacer eso, puede usar 'GetAll ' (o use la agrupación implícita de múltiples registros a través de 'List ', 'T []' o 'IEnumerable ' como se sugiere) (Y las personas que publican/codifican ¡ya que las pruebas nunca publican cosas que explotan!). Tenga en cuenta que Ninject no tiene ningún muchanismt para generar un Composite implícito para multidifundir las llamadas de la manera que desee. –

+1

Esto funciona genial. Gracias. – MikeWyatt

0

Usted no puede obligar a muchas clases concretas a una sola interfaz, que va en contra de las reglas DI.

Lo que básicamente quiere hacer es inicializar un par de instancias concretas y llamar a su método.

Es posible que desee comprobar esto:

Bind<IBreakfast>.To<Spam>().Named("Spam"); 
Bind<IBreakfast>.To<Eggs>().Named("Eggs"); 
Bind<IBreakfast>.To<MoreSpam>().Named("MoreSpam"); 

var breakfastList = new List() { "Spam", "Eggs", "MoreSpam" }; 
breakfastList.ForEach(item => kernel.Get<IBreakfast>(item).Eat()); 
+0

No diría que va en contra de las reglas de DI. Si el dominio de su problema naturalmente se ajusta siempre a una posible relación de uno a varios entre una interfaz y clases concretas, está bien. Los contenedores Decent IoC le permiten modelar este escenario. El escenario del complemento de OP es uno de estos tipos de modelo. –

+3

Este enfoque no funciona con una arquitectura de complemento porque, por definición, no sabe qué complementos estarán presentes. – Bevan