2012-09-10 13 views
17

der Abhängigkeits bewege ich zur Zeit den folgenden Code verwende:Was Anweisung using passiert, wenn ich Injektion

public class MyProvider 
{ 
    public MyProvider() 
    { 
    } 

    public void Fetch() 
    { 
     using (PopClient popClient = new PopClient()) 
     { 
      .... 
     } 
    } 
} 

Weil ich die Fetch-Methode und aufgrund der Tatsache, dass ich kann‘, um Unit-Test in der Lage sein wollen t mock PopClient, ich habe eine Schnittstelle und eine Wrapper-Klasse erstellt, die PopClient aufruft. Meine aktualisierten Code wie folgt aussehen:

public class MyProvider 
{ 
    private readonly IPopClient popClient; 

    public MyProvider(IPopClient popClient) 
    { 
     this.popClient = popClient; 
    } 

    public void Fetch() 
    { 
     using (var pop3 = popClient) 
     { 
      .... 
     } 
    } 
} 

ich Ninject für Dependency Injection verwende und ich bin mir nicht ganz sicher, welche Art von Wirkung der using-Anweisung in dem aktualisierten Code hat seit Ninject bereits eine Instanz von popclient erstellt und injizierte es in den Konstruktor.

Wird die using-Anweisung über das pop3-Objekt verfügen und das popClient-Objekt allein lassen, damit Ninject damit umgehen kann oder wird die using-Anweisung mit Ninject interferieren?

Was ist der richtige Ansatz in diesem Fall? Jede Einsicht wäre sehr hilfreich.

+0

Wenn Sie PopClient disponen, was passiert dann mit dem MyProvider-Objekt? Sollte es nicht auch entsorgt werden? Weil dort nur ein schreibgeschütztes Mitglied in der Klasse übrig bleibt. Wenn es so ist, denke ich, es ist besser, eine dispose-Methode für die MyProvider-Klasse zu verwenden. –

Antwort

14

Die pop3 Variable wird die gleiche Referenz auf ein IPopClient Objekt sein, da popClient hat, also wenn die using Anweisung beendet ist, bezeichnet das Objekt sowohl durch die lokalen und Instanzvariablen entsorgen() d, wahrscheinlich platzieren in einem inkonsistenten Zustand für die weitere Verwendung.

public class MyProvider 
{ 
    private readonly Func<IPopClient> createPopClient; 

    public MyProvider(Func<IPopClient> popClientFactory) 
    { 
     this.createPopClient = popClientFactory; 
    } 

    public void Fetch() 
    { 
     using (var pop3 = createPopClient()) 
     { 
      .... 
     } 
    } 
} 

Wenn Sie jetzt Fetch() anrufen, führen Sie es aus der Fabrik:

Wenn Sie mehrere Instanzen von IPopClient, eine pro Fetch() Anruf verwenden möchten, was Sie sollten eine „Factory-Methode“ zu tun ist zu injizieren Methode, die einen neuen Verweis auf eine IPopClient zurückgibt, die verwendet und dann entsorgt werden kann, ohne irgendeinen anderen Aufruf dieser Methode zu beeinflussen.

AutoFac unterstützt das Einfügen von Factory-Methoden für registrierte Typen ohne zusätzliche Einstellungen (daher der Name, denke ich); Ich glaube, wenn Sie einen Ninject-Container konfigurieren, müssen Sie explizit einen "Getter" als Factory-Methode für einen bestimmten Rückgabetyp registrieren (der so einfach wie ein Lambda ()=>new PopClient() sein kann oder einen Aufruf der Auflösungsmethode des Containers verwenden kann).

+1

besser, um eine Factory-Schnittstelle zu erstellen. Die Absicht ist klarer. +1 für Factory Pattern – jgauffin

+0

Solange Sie 'Ninject.Extensions.Factory.dll' in Ihrem AppDomain.BaseDirectory haben, wird Func automatisch generiert - siehe [das' Ninject.Extensions.Factory' Wiki] (https: // github.com/ninject/ninject.extensions.factory/wiki/Func) (dh keine Notwendigkeit, etwas zu registrieren) –

+0

Ich werde den Kommentar von @jgauffin oben second. Eine Factory-Schnittstelle ist ein bisschen mehr Arbeit, aber es wird sich auf lange Sicht auszahlen. Die Absicht wird klarer und das Spotten ist auch einfacher. – Pflugs

1

Wenn Ihre Bindungen, den Umfang der Einrichtung erklären:

https://github.com/ninject/ninject/wiki/Object-Scopes

Ninject auf die Objekte verfügen rufen wird es für Sie erstellt, so stellen Sie sicher, dass Sie Ihre dispose Methoden in allen Objekten aufzuschreiben Sie geben Ninject zu handhaben.

+0

Das Problem ist, dass MyProvider, wie es derzeit ist, nur eine Instanz eines IPopClient-Objekts verwendet; Das bedeutet, dass, wenn Code mehrere Aufrufe von Fetch() mit einer Instanz von MyProvider ausführt, dies unabhängig vom registrierten Umfang von IPopClient fehlschlägt. – KeithS

+0

Ja, die Fetch-Methode wird mehrmals aufgerufen, so dass ich im aktuellen Code (kein DI) immer eine neue Pop-Instanz wegen der using-Anweisung garantierte. Im DI-Code glaube ich, dass der transiente Bereich nur eine Instanz erstellt, die von mehreren Aufrufen verwendet wird, und die using-Anweisung diese Instanz nach dem ersten Aufruf abschafft. – Thomas

+0

@Thomas - das ist genau richtig - siehe meine Antwort.Kurz gesagt, wenn Sie die using-Anweisung beibehalten möchten, möchten Sie keine einzelne Instanz injizieren, sondern eine Factory-Methode, die Sie aufrufen können, um beliebig viele Instanzen zu erzeugen. – KeithS

Verwandte Themen