Creare un’istanza usando Ninject con parametri aggiuntivi nel costruttore

Ho deciso di iniziare a utilizzare Ninject e affrontare un problema. Dì che ho il seguente scenario. Ho un’interfaccia IService e 2 classi che implementano questa interfaccia. E inoltre ho una class, che ha un costruttore che ottiene IService e un int . Come posso creare un’istanza di questa class con Ninject (non voglio cablare questo int, voglio passarlo ogni volta che ottengo un’istanza)?

Ecco un codice che illustra la situazione:

 interface IService { void Func(); } class StandardService : IService { public void Func() { Console.WriteLine("Standard"); } } class AlternativeService : IService { public void Func() { Console.WriteLine("Alternative"); } } class MyClass { public MyClass(IService service, int i) { this.service = service; } public void Func() { service.Func(); } IService service = null; } class Program { static void Main(string[] args) { IKernel kernel = new StandardKernel(new InlineModule( x => x.Bind().To(), x => x.Bind().ToSelf())); IService service = kernel.Get(); MyClass m = kernel.Get(); m.Func(); } } 

L’object With.ConstructorArgument esisteva in 1.0 per questo scopo. Nella 2.0, la syntax è leggermente cambiata: – With.Parameters.ConstructorArgument con ninject 2.0

Vedi Iniettare il valore nella dipendenza iniettata per maggiori dettagli ed esempi su come usare il contesto, i provider e gli argomenti per passare cose del genere più correttamente.

EDIT: Come Steven ha scelto di far finta che il mio commento sia irrilevante, è meglio chiarire quello che sto dicendo con alcuni esempi (per 2.0):

 MyClass m = kernel.Get( new ConstructorArgument( "i", 2) ); 

che ai miei occhi è molto chiaro e afferma esattamente cosa sta succedendo.

Se sei in una posizione in cui puoi determinare il parametro in un modo più globale, puoi registrare un fornitore e farlo in questo modo:

 class MyClassProvider : SimpleProvider { protected override MyClass CreateInstance( IContext context ) { return new MyClass( context.Kernel.Get(), CalculateINow() ); } } 

E registralo in questo modo:

 x => x.Bind().ToProvider( new MyClassProvider() ) 

NB il bit CalculateINow() è dove inseriresti la tua logica come nella prima risposta.

O renderlo più complesso come questo:

 class MyClassProviderCustom : SimpleProvider { readonly Func _calculateINow; public MyClassProviderCustom( Func calculateINow ) { _calculateINow = calculateINow; } protected override MyClass CreateInstance( IContext context ) { return new MyClass( context.Kernel.Get(), _calculateINow() ); } } 

Quale ti registreresti in questo modo:

 x => x.Bind().ToProvider( new MyClassProviderCustom( ( ) => new Random( ).Next( 9 ) ) ) 

AGGIORNAMENTO: i meccanismi più recenti che presentano pattern molto migliorati con un numero di piastre inferiore rispetto a quelli sopra riportati sono incorporati nell’estensione Ninject.Extensions.Factory , consultare: https://github.com/ninject/ninject.extensions.factory/wiki

Come affermato in precedenza, se è necessario passare ogni volta un parametro diverso e si hanno più livelli nel grafico delle dipendenze, potrebbe essere necessario fare qualcosa di simile .

Un’ultima considerazione è che poiché non si è specificato un Using , verrà eseguito il default come predefinito / predefinito nelle opzioni per il kernel ( TransientBehavior nell’esempio) che potrebbe rendere il fatto che la factory calcola i su il moot della mosca [ad esempio, se l’object è stato memorizzato nella cache]

Ora, per chiarire alcuni altri punti nei commenti che sono stati FUDed e sorvolati. Alcune cose importanti da considerare sull’uso di DI, che si tratti di Ninject o di qualsiasi altra cosa:

  1. Avere il più ansible per iniezione di costruttore, quindi non è necessario utilizzare attributi e trucchi specifici del contenitore. C’è un buon post sul blog su quello che il tuo contenitore IoC sta mostrando .

  2. Minimizza il codice andando al contenitore e chiedendo cose – altrimenti il ​​tuo codice è abbinato a a) il contenitore specifico (che il CSL può minimizzare) b) il modo in cui è strutturato il tuo intero progetto. Ci sono dei buoni post sul blog che dimostrano che CSL non sta facendo quello che pensi che faccia. Questo argomento generale viene definito Service Location vs Dependency Injection . AGGIORNAMENTO: vedere http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx per una spiegazione dettagliata e completa.

  3. Riduci al minimo l’uso di statici e singleton

  4. Non dare per scontato che ci sia solo un contenitore [globale] e che sia giusto richiederlo quando ne hai bisogno come una bella variabile globale. L’uso corretto di più moduli e Bind.ToProvider() offre una struttura per gestirlo. In questo modo ogni sottosistema separato può funzionare autonomamente e non si avranno componenti di basso livello legati a componenti di livello superiore, ecc.

Se qualcuno vuole inserire i link ai blog a cui mi riferisco, lo apprezzerei (sono tutti già collegati da altri post su SO, quindi tutto ciò è solo una duplicazione UI introdotta con l’objective di evitare la confusione di una risposta fuorviante.)

Ora, se solo Joel potesse entrare e davvero mi ha impostato direttamente sulla syntax e / o il modo giusto per farlo!

AGGIORNAMENTO: Mentre questa risposta è chiaramente utile dal numero di voti ottenuti, vorrei fare i seguenti consigli:

  • Quanto sopra sembra un po ‘datato e ad essere onesti riflette un sacco di pensieri incompleti che sembrano quasi imbarazzanti dopo aver letto Dependency Injection in .net – Corri e compralo subito – non si tratta solo di DI, il primo semestre è un trattamento completo di tutte le preoccupazioni di architettura che lo circondano da un uomo che ha passato troppo tempo qui aggirando il tag di dipendenza dipendenza.
  • Leggi subito i post più votati di Mark Seemann qui su SO : imparerai preziose tecniche da ognuno