Ich bin ziemlich vertraut mit der Abhängigkeitsinjektion mit NInject in MVC3. Während der Arbeit in einer MVC3-Anwendung habe ich mit NInject eine benutzerdefinierte Controller Creation Factory entwickelt, sodass in jeden Controller, der erstellt wird, Abhängigkeiten über diese Controller Factory eingefügt werden.
Jetzt beginne ich mit der Entwicklung einer Windows-Anwendung. Ich möchte die anwendungsweite Abhängigkeitsinjektion verwenden. Das heißt, jedes Objekt muss über NInject erstellt werden, um das Testen von Einheiten zu vereinfachen. Bitte leiten Sie mich, um sicherzustellen, dass jedes erstellte Objekt nur von der NInject Factory stammt.
Wenn Button_Click
ich zum Beispiel in einem Windows-Formular bei einem Ereignis schreibe:
TestClass testClass = new TestClass()
und TestClass
hat eine Abhängigkeit von, sagen wir, ITest
dann muss es automatisch aufgelöst werden. Ich weiß, dass ich verwenden kann:
Ikernel kernel = new StandardKenel()
//AddBinding()
TestClass testClass = kenel.get<TestClass>();
Aber ich finde es mühsam, dies jedes Mal zu tun, wenn ich ein Objekt erstellen möchte. Es zwingt auch den Entwickler, das Objekt auf eine bestimmte Art und Weise zu erstellen. Kann es besser gemacht werden?
Kann ich ein zentrales Repository für die Objekterstellung haben und dann verwendet jede Objekterstellung automatisch dieses Repository?
quelle
Antworten:
Für Clientanwendungen ist es häufig am besten, ein Muster wie MVP (oder MVVM) anzupassen und die Datenbindung vom Formular zum zugrunde liegenden ViewModel oder Presenter zu verwenden.
Für die ViewModels können Sie die erforderlichen Abhängigkeiten mithilfe der Standardkonstruktorinjektion einfügen.
Im Composition Root Ihrer Anwendung können Sie das gesamte Objektdiagramm für Ihre Anwendung verbinden. Sie müssen dafür keinen DI-Container (wie z. B. Ninject) verwenden, können dies aber.
quelle
Windows Forms-Anwendungen haben normalerweise einen Eintrittspunkt, der wie folgt aussieht:
Wenn Sie diesen Punkt in Code zu Ihrem Kompositionsstamm machen , können Sie die Anzahl der Stellen, an denen Sie Code haben, der Ninject explizit aufruft, wie bei einem Service Locator, erheblich reduzieren.
Ab diesem Zeitpunkt injizieren Sie alle Abhängigkeiten über die Konstruktorinjektion.
Wenn Ihre "Abhängigkeit" etwas ist, das Sie in der Lage sein müssen, mehrmals zu produzieren, dann ist das, was Sie wirklich brauchen, eine Fabrik:
Sie können die IFactory-Schnittstelle auf diese Weise implementieren, um zu vermeiden, dass Tonnen von einmaligen Implementierungen erstellt werden müssen:
quelle
InjectionFactory<T>
implementiert habe, loswerden , sollte der bereitgestellte Code einwandfrei funktionieren. Gibt es etwas Besonderes, mit dem Sie Probleme haben?Type
können, die aber garantieren würde, dass die Objekte, für die es hydriert wurdeType
, einen bestimmten generischen Typ implementieren oder erweitern. Nichts zu spezielles.Ich schreibe immer einen Adapter-Wrapper für jeden IoC-Container, der so aussieht:
Insbesondere für Ninject sieht die konkrete Adapterklasse folgendermaßen aus:
Der Hauptgrund dafür ist, das IoC-Framework zu abstrahieren, sodass ich es jederzeit ersetzen kann, da der Unterschied zwischen den Frameworks im Allgemeinen in der Konfiguration und nicht in der Verwendung liegt.
Als Bonus wird es jedoch auch viel einfacher, das IoC-Framework in anderen Frameworks zu verwenden, die es von Natur aus nicht unterstützen. Für WinForms sind es beispielsweise zwei Schritte:
Instanziieren Sie in Ihrer Main-Methode einfach einen Container, bevor Sie etwas anderes tun.
Und dann haben Sie eine Basisform, von der andere Formen ableiten, die Inject auf sich selbst aufruft.
Dies weist die Autoverkabelungsheuristik an, zu versuchen, alle Eigenschaften in dem Formular rekursiv einzufügen, das den in Ihren Modulen festgelegten Regeln entspricht.
quelle
Eine gute Verwendung von Dependency Injection beruht normalerweise auf der Trennung des Codes, mit dem Objekte erstellt werden, und der eigentlichen Geschäftslogik. Mit anderen Worten, ich möchte nicht, dass mein Team auf diese Weise häufig
new
eine Instanz einer Klasse verwendet und erstellt. Sobald dies erledigt ist, gibt es keine Möglichkeit, den erstellten Typ einfach gegen einen anderen auszutauschen, da Sie den konkreten Typ bereits angegeben haben.Es gibt also zwei Möglichkeiten, dies zu beheben:
TestClass
in Ihrem Beispiel ein in Ihr Windows Form ein, sodass es bereits eine Instanz hat, wenn es benötigt wird. Wenn Ninject Ihr Formular instanziiert, wird die Abhängigkeit automatisch erstellt.IKernel
in Windows Form eine einfügen und diese dann zum Instanziieren verwendenTestClass
. Abhängig von Ihrem Stil gibt es auch andere Möglichkeiten, dies zu erreichen (Injizieren einer Fabrikklasse, eines Fabrikdelegierten usw.).Dadurch ist es einfach, sowohl den konkreten TestClass-Typ als auch die tatsächliche Konstruktion der Testklasse auszutauschen, ohne den Code zu ändern, der die Testklasse verwendet .
quelle
Ich habe Ninject nicht verwendet, aber die Standardmethode zum Erstellen von Inhalten bei Verwendung einer IoC ist, dies über einen Bereich zu tun,
Func<T>
in demT
der Typ des Objekts angegeben ist, das Sie erstellen möchten. Wenn also ein ObjektT1
Objekte vom Typ erstellen muss, mussT2
der Konstruktor vonT1
einen Parameter vom Typ haben,Func<T1>
der dann als Feld / Eigenschaft von gespeichert wirdT2
. Nun , wenn Sie Objekte des Typs schaffenT2
inT1
rufen Sie auf derFunc
.Dies entkoppelt Sie vollständig von Ihrem IoC-Framework und ist der richtige Weg, um in einer IoC-Denkweise zu programmieren.
Der Nachteil dabei ist, dass es ärgerlich werden kann, wenn Sie
Func
s manuell verdrahten müssen oder wenn Ihr Ersteller beispielsweise einige Parameter benötigt, sodass die IoC das nicht automatisch verdrahten kannFunc
für Sie kann.http://code.google.com/p/autofac/wiki/RelationshipTypes
quelle