Dies ist eigentlich einfach, wenn Sie erst einmal verstanden haben, dass es bei DI um Muster und Prinzipien geht , nicht um Technologie.
Befolgen Sie diese allgemeinen Prinzipien, um die API DI Container-unabhängig zu gestalten:
Programm auf eine Schnittstelle, keine Implementierung
Dieses Prinzip ist eigentlich ein Zitat (allerdings aus dem Gedächtnis) aus Design Patterns , aber es sollte immer Ihr eigentliches Ziel sein . DI ist nur ein Mittel, um dieses Ziel zu erreichen .
Wenden Sie das Hollywood-Prinzip an
Das Hollywood-Prinzip in DI-Begriffen lautet: Rufen Sie nicht den DI-Container an, er ruft Sie an .
Fragen Sie niemals direkt nach einer Abhängigkeit, indem Sie einen Container aus Ihrem Code heraus aufrufen. Fragen Sie implizit mit Constructor Injection danach .
Verwenden Sie die Konstruktorinjektion
Wenn Sie eine Abhängigkeit benötigen, fordern Sie diese statisch über den Konstruktor an:
public class Service : IService
{
private readonly ISomeDependency dep;
public Service(ISomeDependency dep)
{
if (dep == null)
{
throw new ArgumentNullException("dep");
}
this.dep = dep;
}
public ISomeDependency Dependency
{
get { return this.dep; }
}
}
Beachten Sie, wie die Service-Klasse ihre Invarianten garantiert. Sobald eine Instanz erstellt wurde, ist die Abhängigkeit aufgrund der Kombination aus der Guard-Klausel und dem readonly
Schlüsselwort garantiert verfügbar .
Verwenden Sie Abstract Factory, wenn Sie ein kurzlebiges Objekt benötigen
Mit Constructor Injection injizierte Abhängigkeiten sind in der Regel langlebig, aber manchmal benötigen Sie ein kurzlebiges Objekt oder erstellen die Abhängigkeit basierend auf einem Wert, der nur zur Laufzeit bekannt ist.
Sehen Sie diese für weitere Informationen.
Verfassen Sie nur im letzten verantwortlichen Moment
Halten Sie Objekte bis zum Ende entkoppelt. Normalerweise können Sie warten und alles am Einstiegspunkt der Anwendung verkabeln. Dies wird als Kompositionswurzel bezeichnet .
Weitere Details hier:
Vereinfachen Sie die Verwendung einer Fassade
Wenn Sie der Meinung sind, dass die resultierende API für Anfänger zu komplex wird, können Sie immer einige Facade- Klassen bereitstellen , die allgemeine Abhängigkeitskombinationen enthalten.
Um eine flexible Fassade mit einem hohen Grad an Auffindbarkeit bereitzustellen, können Sie Fluent Builders bereitstellen. Etwas wie das:
public class MyFacade
{
private IMyDependency dep;
public MyFacade()
{
this.dep = new DefaultDependency();
}
public MyFacade WithDependency(IMyDependency dependency)
{
this.dep = dependency;
return this;
}
public Foo CreateFoo()
{
return new Foo(this.dep);
}
}
Dies würde es einem Benutzer ermöglichen, ein Standard-Foo durch Schreiben zu erstellen
var foo = new MyFacade().CreateFoo();
Es wäre jedoch sehr auffindbar, dass es möglich ist, eine benutzerdefinierte Abhängigkeit anzugeben, und Sie könnten schreiben
var foo = new MyFacade().WithDependency(new CustomDependency()).CreateFoo();
Wenn Sie sich vorstellen, dass die MyFacade-Klasse viele verschiedene Abhängigkeiten kapselt, hoffe ich, dass klar ist, wie sie die richtigen Standardeinstellungen liefert und gleichzeitig die Erweiterbarkeit erkennbar macht.
FWIW, lange nachdem ich diese Antwort geschrieben hatte, erweiterte ich die hierin enthaltenen Konzepte und schrieb einen längeren Blog-Beitrag über DI-freundliche Bibliotheken und einen Begleitbeitrag über DI-freundliche Frameworks .