2010-06-17 6 views
5

Ich versuche, mit einer einfachen Abhängigkeitsinjektion mit C# zu beginnen und bin auf ein Problem gestoßen, für das ich keine Antwort zu finden vermag.C# Abhängigkeitsinjektion - wie injiziert man eine Abhängigkeit ohne Quelle?

Ich habe eine Klasse, die von einer anderen Abteilung geschrieben wurde, für die ich die Quelle in meinem Projekt nicht habe. Ich wollte ein Objekt dieses Typs durch einen Konstruktor unter Verwendung einer Schnittstelle einfügen, aber natürlich kann ich die Implementierung der injizierten Objekte nicht ändern, um die Schnittstelle zu implementieren, um Polymorphie zu erreichen, wenn das Objekt auf den Schnittstellentyp umgesetzt wird.

Jedes akademische Beispiel, das ich jemals von dieser Technik gesehen habe, verwendet Klassen, die Klassen verwenden, die im Projekt selbst deklariert werden. Wie würde ich meine Abhängigkeit injizieren, ohne dass die Quelle im Projekt verfügbar ist?

Ich hoffe, das macht Sinn, danke.

Antwort

0

Wenn Sie nichts in einer Klasse ändern müssen, brauchen Sie den Code kaum. Nehmen wir an, Sie haben eine Klasse X in einer DLL, die Sie in eine andere Klasse Y injizieren möchten, die Sie schreiben. In solch einem Fall können Sie eine Instanz von X erstellen und als Parameter in den Konstruktor von Y eingeben. Das sieht etwa so aus:

Fügen Sie einen Verweis auf die DLL mit der Klasse X in Ihrem Projekt hinzu.

Use NameSpaceOfX; 
Class Y 
{ 
    Public Y() //Default constructor 
    { 
    } 

    Public Y(X instanceOfX) 
    { 
     //Use instanceOfX here as required 
    } 
} 

In Ihrem Haupt-Code:

//Create instance of X 
X instanceOfX = new X(); 
//Inject it into Y 
Y instanceOfY = new Y(instanceOfX); 
//Use Y now. 
6

Sie einen Wrapper um Ihre Zieltyp erstellen können, so zum Beispiel eine Klasse haben könnten sie bieten:

public class TheirClass 
{ 
    public void DoSomething(); 
} 

Mit dem Sie können eine Schnittstelle definieren:

public interface ITheirClass 
{ 
    void DoSomething(); 
} 

Und diese Schnittstelle auf einer Wrapper-Klasse implementieren:

public class TheirClassWrapper : TheirClass, ITheirClass 
{ 

} 

Oder, wenn die Klasse, die sie zur Verfügung gestellt verschlossen ist, müssen Sie es etwas anders machen:

public class TheirClassWrapper : ITheirClass 
{ 
    private TheirClass instance = new TheirClass(); 

    public void DoSomething() 
    { 
    instance.DoSomething(); 
    } 
} 

Dann können Sie diese Schnittstelle statt injizieren.

Ich weiß in MEF können wir Betontypen exportieren und haben sie richtig injiziert, aber ich bin mir nicht sicher über andere IoC-Container.

+0

das war genau das, was ich dachte. – Steven

+0

Adaptermuster. Guter Ruf. – Wix

1

Die Frage ist, warum möchten Sie es als Schnittstelle injizieren? Liegt es daran, dass die Klasse einige Eigenschaften/Methoden implementiert, die Sie abstrahieren möchten, um sie zu ersetzen, oder wenn Sie nur versuchen, eine Marker-Schnittstelle darauf zu "zwingen", weil "wir immer von Schnittstellen und nicht von konkreten Klassen abhängig sind" ? Wenn es das letztere ist, dann bist du auf dem falschen Weg, da du es wahrscheinlich sowieso sofort auf den Beton werfen würdest.

die ehemaligen der beiden Unter der Annahme, kann ich zwei Optionen:

  1. Verwenden Vererbung statt. Je nachdem, ob die Klasse erstellt wurde, ist dies möglicherweise möglich oder nicht. Sie können jedoch davon erben und Ihre neue Klasse durch die alte ersetzen.
  2. Erstellen Sie die Schnittstelle mit den von Ihnen benötigten Methoden/Eigenschaften und umschließen Sie die externe konkrete Klasse in einer Klasse, die die Schnittstelle implementiert.

Für Option 2, wenn Sie nicht erben kann, als ein Beispiel, vorausgesetzt, Sie sind nur etwa ein Verfahren in der Klasse kümmern (wir nennen es Method1()) Sie eine passende Schnittstelle für sie erstellen:

public interface IMyNewInterface 
{ 
    void Method1(); 
} 

Dann eine Implementierung es schaffen, die die konkrete Klasse als Abhängigkeit (von Ihrem Container als normal eingespritzt) hat, die nur die konkrete Klasse ruft:

public class MyNewClass : IMyNewInterface 
{ 
    private MyConcreteClass _MyConcreteClass; 

    public void MyNewClass(MyConcreteClass concreteClass) 
    { 
     _MyConcreteClass = concreteClass; 
    } 

    public void Method1() 
    { 
     _MyConcreteClass.Method1(); 
    } 
} 
+0

Aber mit der letzten der beiden Optionen, wäre es möglich, Unit-Test eigene Klasse, die die 3rd-Party-Klasse als ein Argument verwendet, um den Konstruktor übergeben. d. h., es wäre möglich, TheirClass mit ITheirClass zu simulieren –

+0

Beide Optionen ermöglichen es Ihnen, ihre Klasse (Generika beiseite) zu ersetzen, der Schnittstellenansatz wäre jedoch meine Präferenz. –

+0

Sorry, ich meine nicht die Optionen 1 und 2. Bezieht sich auf die "..wir immer abhängen ..." Zitat. Vielleicht habe ich es falsch gelesen. Vielleicht meintest du, dass es nicht nur getan werden sollte, um getan zu werden. Aber gute Praktiken bedeuten, dass wir den Weg für zukünftige Änderungen oder Wartung ebnen. Wenn die Klasse injiziert würde, würde es es einfacher machen, sie beispielsweise mit einer AOP-Leistungsmessung zu injizieren. –

Verwandte Themen