2010-03-07 6 views
6

Si consideri il seguente:Ninject 2.0 - associazione a un oggetto che utilizza la stessa interfaccia più di una volta?

public Something(IInterface concreteObjectOne, IInterface concreteObjectTwo) 
    { 
     this.concreteObjectOne = concreteObjectOne; 
     this.concreteObjectTwo = concreteObjectTwo; 
    } 

Come faccio a impostare impostato questo tipo di legame con Ninject? Proverò a cercare su Google il termine, ma siccome non sono sicuro di come si chiami non posso, né posso trovare nulla sul Wiki a riguardo.

Edit:

Credo che questo si chiama convenzione basata Binding, come descritto here. Tuttavia questa documentazione è per la versione 1.0 e 2.0 non ha il metodo Only. Mi piacerebbe che questo fosse raggiunto senza attributi - usando la convenzione dei nomi o qualcosa di simile.

risposta

9

Oltre all'utilizzo del metodo "Solo", l'articolo suggerisce un'altra soluzione specificando attributi diversi per gli oggetti iniettati.

Esempio:

public class ObjectOneAttribute : Attribute 
{ 

} 
public class ObjectTwoAttribute : Attribute 
{ 

} 

Poi

public Something([ObjectOneAttribute] IInterface concreteObjectOne, [ObjectTwoAttribute] IInterface concreteObjectTwo) 
    { 
     this.concreteObjectOne = concreteObjectOne; 
     this.concreteObjectTwo = concreteObjectTwo; 
    } 

E quando si desidera associare l'interfaccia per l'oggetto concreto corretto, utilizzare il metodo "WhereTargetHas":

Bind<IInterface>().To<YourConcreteTypeOne>().WhereTargetHas<ObjectOneAttribute>(); 
Bind<IInterface>().To<YourConcreteTypeTwo>().WhereTargetHas<ObjectTwoAttribute>(); 

Aggiornamento: soluzione senza utilizzando gli attributi:
utilizzare il metodo "Quando":

Bind<IInterface>().To<YourConcreteTypeOne>().When(r => r.Target.Name == "concreteObjectOne"); 
Bind<IInterface>().To<YourConcreteTypeTwo>().When(r => r.Target.Name == "concreteObjectTwo") 

;

+0

Preferisco non aggiungere attributi. La fine dell'articolo mostra come utilizzare la convenzione, ad es. il parametro si chiama X. Questo è quello che cerco davvero. – Finglas

+0

@Finglas Ho aggiornato con un'altra soluzione –

+0

È eccellente. Ero vicino quando stavo giocando per farlo funzionare, ma tu sei perfetto. A proposito, non ho nulla contro gli attributi, ma trovo che in questo scenario sia uno spreco. Questo tipo di configurazione non è comune nella mia base di codice, quindi usare il metodo When è molto più bello. Saluti. – Finglas

5

Se è possibile fornire alcune indicazioni generali, anziché specifiche di Ninject, suggerirei di riconsiderare leggermente il progetto. Il costruttore corrente è vago perché non offre alcuna guida su quale implementazione di IInterface va dove: mi rendo conto che questo è solo un simulatore della tua vera API e mentre la vera API può offrire più aiuto allo sviluppatore umano in la forma di parametri opportunamente denominati, una macchina come un contenitore DI non può inferire l'uso corretto.

Molti DI Container offrono un modo per risolvere tale vaghezza, ad esempio fornendo attributi che è possibile utilizzare per associare nomi (metadati) a ciascuna dipendenza. AFAIR, Ninject ha Inject attributi ...

Tuttavia, prendere in considerazione un paio di alternative:

La prima alternativa è quella di incapsulare le due istanze un'interfaccia simile a un oggetto Parametro, in questo modo:

public interface IParameterObject 
{ 
    IInterface ObjectOne { get; } 

    IInterface ObjectTwo { get; } 
} 

Ora è possibile modificare il costruttore per prendere un'istanza di IParameterObject invece delle due istanze dell'interfaccia.

public Something(IParameterObject po) 
{ 
    this.concreteObjectOne = po.ObjectOne; 
    this.concreteObjectTwo = po.ObjectTwo; 
} 

Questo significa che è possibile spingere la configurazione del IParameterObject al Composition Root.

Un'altra alternativa a riflettere è se ha senso prendere in considerazione il caso di due istanze come solo un caso speciale di un disegno più generale che prende qualsiasi numero di istanze. Questo non può essere sempre il caso, ma se lo è, è possibile modificare il costruttore per questo:

public Something(IEnumerable<IInterface> objects) 

Io personalmente preferirei uno qualsiasi dei suggerimenti di cui sopra su tutto ciò che utilizza specifiche caratteristiche Ninject, perché mi costringe a rendere l'API più esplicita in generale, e quindi più leggibile e mantenibile.

+0

@ Mark. La tua risposta di ieri (grazie ancora) mi ha spinto a utilizzare una fabbrica per utilizzare il modello di progettazione della strategia per i miei algoritmi plug-in. Le fabbriche in questione ora prendono i due oggetti concreti, ma dal momento che sto usando il modello di strategia sono entrambi della stessa interfaccia. Normalmente senza IOC dovrei scrivere un codice come questo e collegare manualmente le dipendenze. Rende anche facile il test delle unità. Mentre quello che hai suggerito avrebbe funzionato, in qualche modo sento che non è necessario. Con 2.0 non riesco a trovare il modo corretto di fare altro che un semplice binding. – Finglas

+0

Abbastanza buono - felice che tu abbia trovato una soluzione :) –