2011-09-17 14 views
6

Sento che mi manca qualcosa di ovvio. Ho letto diverse domande correlate qui e ho letto la pagina dei binding contestuali aggiornata sul wiki di Ninject ma purtroppo continua a non funzionare.Ninject binding with WhenInjectedInto metodo di estensione

Sto tentando di installare in un secondo momento un'applicazione legacy che utilizzava un pattern factory per utilizzare Ninject.

Ho 1 interfaccia (IInterface) implementata da 2 classi (ClassB e ClassC). IInterface ha un metodo di caricamento. Nel metodo di caricamento di ClassB crea un'istanza di ClassC e quindi esegue il suo metodo di caricamento.

Fondamentalmente il flusso del programma è ClasseA crea ClassB ed esegue il metodo di caricamento. Nel metodo di caricamento ClassB crea ClassC che funziona.

miei attacchi sono settati come così ...

Bind<IInterface>().To<ClassC>().WhenInjectedInto<ClassB>(); 
Bind<IInterface>().To<ClassB>().WhenInjectedInto<ClassA>(); 

Quando questo viene eseguito non riesce a metodo load di ClassB con questo errore ...

errore che attiva IInterface Nessun attacchi di corrispondenza sono disponibili, e il il tipo non è autoindicabile.

Se provo quanto segue ...

Bind<IInterface>().To<ClassC>().WhenInjectedInto<ClassB>(); 
Bind<IInterface>().To<ClassB>(); 

Fa un ciclo infinito e non crea mai ClassC.

EDIT ho semplificato questo in una prova di unità che passa, ma non mi dà i risultati che voglio ...

[TestClass] 
public class NinjectTestFixture 
{ 
    private interface IDoSomething 
    { 
     void SaySomething(); 
    } 

    private class ClassA : IDoSomething 
    { 
     public void SaySomething() 
     { 
      Console.WriteLine("Hello from Class A"); 
     } 
    } 

    private class ClassB : IDoSomething 
    { 
     private IKernel _Kernel; 

     public ClassB(IKernel kernel) 
     { 
      _Kernel = kernel; 
     } 

     public void SaySomething() 
     { 
      Console.WriteLine("Hello from Class B"); 

      var x = _Kernel.Get<IDoSomething>(); 

      x.SaySomething(); 
     } 
    } 

    private class ClassC 
    { 
     private IKernel _Kernel; 

     public ClassC(IKernel kernel) 
     { 
      _Kernel = kernel; 
     } 

     public void SaySomething() 
     { 
      Console.WriteLine("Hello from Class C"); 

      var x = _Kernel.Get<IDoSomething>(); 

      x.SaySomething(); 
     } 
    } 

    [TestMethod] 
    public void TestMethod1() 
    { 
     var kernel = new StandardKernel(); 

     kernel.Bind<IDoSomething>().To<ClassA>(); 
     kernel.Bind<IDoSomething>().To<ClassB>().WhenInjectedInto<ClassC>(); 
     kernel.Bind<ClassC>().ToSelf(); 

     var x = kernel.Get<ClassC>(); 

     x.SaySomething(); 
    } 

L'output è: Ciao da Classe C Ciao dalla classe A

Ma io voglio: Ciao dalla classe C Ciao dalla classe B Ciao dalla Classe A

Grazie

risposta

6

Si sono non iniezione in ClassC. Stai passando il kernel e risolvendo IDoSomething direttamente da esso. C'è una grande differenza.

Non passare il kernel come parametro: non si tratta di Dipendenza iniezione, ma di posizione di servizio (buon articolo sulla differenza: Service Locator is an Anti-Pattern).

Change ClassC di essere:

private class ClassC  
{   
    private IDoSomething _doSomething;   
    public ClassC(IDoSomething doSomething) 
    {    
     _doSomething = doSomething;   
    }   

    public void SaySomething()   
    {    
     Console.WriteLine("Hello from Class C");    
     //var x = _Kernel.Get<IDoSomething>();    
     _doSomething.SaySomething();   
    }  
} 

Si dovrebbe anche fare le stesse modifiche ClassA e ClassB (passa il tipo/interfaccia che si desidera risolto, non il kernel).

+0

Capisco cosa stai dicendo, ma nel metodo SaySomething ho bisogno di istanziare un oggetto per fare un po 'di lavoro. Nella stessa classe ci sono altri metodi che istanziano i metodi per fare più lavoro. Se avessi fatto ciò che stai suggerendo avrei circa 20 parametri nel mio costruttore. Il codice è stato originariamente scritto oltre 6 anni fa, quindi sto provando ad aggiornarlo gradualmente con DI.Mi sono tormentato su come fare questo e passare il kernel era la soluzione più semplice che avesse più senso. Ho guardato il luogo del servizio e questo non aveva senso dato l'attuale base di codice. – oliwa

+0

La tua risposta è corretta. Quando ho apportato le modifiche che hai proposto, ho ottenuto i risultati che mi aspettavo. – oliwa

+0

Capisco cosa intendi: anche io ho rifatto i sistemi in cui ho dovuto usare alcuni passaggi intermedi dispari/orribili per introdurre DI. –

Problemi correlati