2011-10-31 12 views
8

voglio legare più implementazioni di un servizio e hanno tutti loro chiamati in una sola volta:Ninject multicasting

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 non lo fa così, e un'eccezione di avere più associazioni. C'è un modo per aggirare quell'errore e avere tutte le implementazioni chiamate?

Inoltre, le chiamate Bind<> possono essere in diversi progetti che possono essere caricati o meno in fase di esecuzione, pertanto la creazione di una singola implementazione per chiamarli non funzionerà. Questo fa parte di un'architettura plug-in per un sito Web ASP.NET MVC 3.

risposta

12

Se si utilizza l'iniezione del costruttore e si dispone di un parametro List<IBreakfast>, quindi Ninject costruirà un elenco utilizzando tutti i collegamenti. È quindi possibile chiamare Eat su queste istanze.

È possibile utilizzare questo modello per ottenere da Ninject la creazione di un elenco di plug-in, ad esempio.

[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 { } 

uscita:

Uova
Spam
MoreSpam

+0

cercherò questo la mattina quando arrivo al lavoro, ma non si Ninject genera un errore sulla seconda chiamata a 'Bind <> () .Per <>() '? – MikeWyatt

+5

@MikeWyatt: No, multipli 'Bind's vanno bene. Ciò che non va bene è andare a 'Get ' che produce più di un oggetto 'Single'. Se vuoi farlo, puoi usare 'GetAll ' (o usare il raggruppamento implicito di più registrazioni tramite 'Lista ', 'T []' o 'IEnumerable ' come suggerito) (E le persone che pubblicano/codice come test non pubblicare mai cose che esplodono!). Nota che Ninject non ha alcun muchanismt per generare un Composito implicito per multicastare le chiamate nel modo desiderato. –

+1

Funziona alla grande. Grazie. – MikeWyatt

0

Non si può legare molte classi concrete a un'unica interfaccia, una volta, che è contro le regole DI.

Ciò che in pratica si vuole fare è inizializzare un paio di istanze concrete e chiamare il loro metodo.

Si consiglia di controllare questo fuori:

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

Non direi che è contro le regole DI. Se il dominio del problema si adatta naturalmente a una relazione potenziale uno-a-molti tra un'interfaccia e classi concrete, allora va bene. Contenitori IoC decenti ti permettono di modellare questo scenario. Lo scenario di plugin dell'OP è uno di questi tipi di modello. –

+3

Questo approccio non funziona con un'architettura plug-in perché, per definizione, non si conoscono i plug-in presenti. – Bevan