Benutzer mit den meisten Antworten
Dependency Injection -- Abhängigkeit Injektion

Frage
-
Hallo,
doch nochmals eine kleine Verständnisfrage.>Es gibt eine Menge guter Tutorial zu DI-Containern im Netz.
>Mir war hier nur wichtig, vorzustellen, warum man DI-Container unbedingt
>braucht und welchen Nutzen sie haben.
Ich suche einfach eine gute Erklärung, ähnlich dem MEFIn dem unteren Artikel wird der Umgang mit dem Managed Extensibility Framework (MEF) anhand einer simplen Anwendung demonstriert. Das Beispiel wird dabei so minimal wie möglich gehalten, damit das Thema leicht verständlich bleibt.
http://www.edvsz.hs-osnabrueck.de/fileadmin/user/huelsmann/
Vielleicht hat jemand eine Uni Vorlesungsscript.Was einfach hilfreich wäre.
Klassisch -- mit C# (händisch) -- LightCore
Dann sieht man die Unterschiede und könnte beurteilen, ob es hilfreich ist.Grüße Oliver
class PersonA(); class PersonB(); class PersonC(); class PersonD(); //Hauptanwendung var pA = new PersonA() var pB = new PersonB() var pC = new PersonC() var pD = new PersonD() //Ist schlecht, neue Klasse, neues Objekt, neue EXE, neu kompilieren. //Besser Interface var p = new Person() //Aber warum ist es jetzt das Problem den new Operator in der Hauptanwendung zu machen. //Ich könnte doch da dann auch jede DLL reinlegen, die das Interface implementiert. //Klar dann hat die Hauptanwendung Kenntnis davon. //Jetzt wird eben die Erzeugung in der Assembly durchgeführt. //Letztendlich habe ich doch keine Vorteile. //Es gibt sicher welche, sonst wurde man es ja nicht machen. // >>Aber in PersonFactory selbst muss der Preis dann doch bezahlt werden: interface IPerson { } class Person : IPerson { } void ChangeName(IPerson person) { } IPerson person = PersonFactory.Create(); class PersonFactory { public static IPerson Create() { // hier binden wir N Stellen im Code an // die konkrete Implementation von Person fest. return new Person(); } } class SimplicissimusContainer { public static T Resolve<T>(string typeName) { Assembly typeAssembly = Assembly.GetEntryAssembly(); Type foundType = typeAssembly.GetType(typeName); T result = (T)Activator.CreateInstance(foundType); return result; } } IPerson person = SimplicissimusContainer.Resolve<IPerson>("WindowsFormsApplication1.Person"); person.FirstName = "Hans"; person.LastName = "Mustermann";
http://de.wikipedia.org/wiki/Dependency_Injection
Teil 1 - abstrakt --> alles klar
Teil 2 - weniger klar, verständlich
Antworten
-
Hallo Oliver,
"brauchbar" ist ein sehr dehnbarer Begriff.
Das MEF-Tutorial auf das Du verweist z.B., ist für einen allerersten Kontakt mit MEF "brauchbar", aber Du wirst anhand dieses Materials nicht wirklich verstehen, was MEF ist.
Viel eher bist Du am Ziel wenn Du dich durch die Artikelserie von Stefan Henneken durcharbeitest:
MEF Teil 1 - Grundlagen, Imports und Exports
MEF Teil 2 – Metadaten und Erstellungsrichtlinien
MEF Teil 3 – Lifecycle beeinflussen und überwachen
MEF Teil 4 – Vererbung mit Composable Parts
MEF Teil 5 – Composition und Recomposition
MEF Teil 6 – Constructor-Injection
MEF Teil 7 – Exportieren über eine Class Factory
MEF Teil 8 – Eigenen ExportProvider erstellen
MEF Teil 9 – Zugriff auf Composable Parts und Metadaten ohne Lazy<>
MEF Teil 10 – Parts über ExportProvider und App.config in AppDomain laden
MEF Teil 11 – Neuerungen unter .NET 4.5
MEF und LightCore sind zwei ziemlich verschiedene Konstrukte, weshalb man sie schlecht vergleichen kann.
Das Managed Extensibility Framework zum einen ist nur bedingt ein IoC-Container. Sein Hauptziel besteht darin, die eigene Anwendung um unbekannte plugin-ähnliche Module zur Laufzeit zu erweitern. MEF hat ausgefeilte Möglichkeiten, benötigte Parts zu suchen und obwohl Komposition mit MEF möglich ist, ist die Komposition nicht das Hauptanliegen von MEF.
LightCore auf der anderen Seite ist eher ein klassischer IoC-Container, das Autofac ähnelt. Die Features werden minimalistisch gehalten, damit eine gute Performanz erreicht wird. Anders als bei MEF sind die Typen mit denen man arbeitet i.d.R. bekannt. Es geht hier primär um dependecy injection und um Auflösen von Kopplung zwischen den Klassen. Zwar kann man auch in MEF Konstruktor-Injektion verwenden, aber in einem viel geringeren Umfang und mit weniger Optionen. Beispiele für die Verwendung findest Du auf der Seite des Autors, ich weiß nicht was daran unverständlich sein soll. Ansonsten verwende bitte die Suchmaschine deiner Wahl, es mangelt nicht an Beispielen zu LightCore.
Gruß
Marcel- Als Antwort markiert Oliver Stippe Dienstag, 3. September 2013 18:24
Alle Antworten
-
Hallo Oliver und Brian,
ich muss Brian Recht geben: Oliver, Du nimmst dir viel zu wenig Zeit dafür, deine Ideen in klare Worte zu fassen. Aber in einem hast auch Du Recht: Der zweite Teil des verlinkten Blogartikels ist tatsächlich weniger verständlich. Ich würde deshalb beim Lesen den abstract factory-Exkurs samt Grafik überspringen und mich einfach auf die interessantere Code-Auflistung konzentrieren.
Peter Bucher zeigt uns hier eine ältere Version des DI-Containers, damals noch AutoFuncContainer genannt. Außer der Grundfunktionalität eines Containers hat die Klasse wenig mit der aktuellen Implementation von LightCore gemeinsam. Aber das ist gerade der Vorteil dieses Codes. Man kann leichter verstehen, was ein DI-Container im wesentlichen ist.
Sehen wir uns den Aufbau der Klasse an. Unser AutoFuncContainer implementierte die Schnittstelle IContainer. Über die zwei öffentlichen Methoden Register() und Resolve() wird die Grundfunktionalität eines Containers implementiert: ein Container muss ein Mapping, eine Zuordnung zwischen einem sog. Vertrags-Typ (Klasse, Schnittstelle) und einer konkreten Implementierung speichern und auflösen können.
Über Register(TContract, TImplementation) ordnet man einem Vertrags-Typ einen bestimmten konkreten Typ zu und speichert dieses Mapping in ein internes Dictionary-Objekt.
Gruß
Die Methode Resolve(TContract) ist dann das Gegenstück dazu: Sie nimmt ein Vertrags-Typ als Argument, schlägt es im Dictionary nach und gibt eine Instanz des damit verknüpften Implementations-Typs zurück.
Von der Funktionalität her ist der AutoFuncContainer-Code sehr ähnlich zu dem Code, das ich in einem anderen Posting gezeigt hatte. Nur dass bei Peter Bucher zusätzlich noch Instanz-Konstruktoren mit Parametern und Instanz-Lebenszyklen unterstützt werden.Marcel
-
beim Durchlesen deines Textes ist mir spontan die Frage aufgekommen was du genau wissens willst....
Hallo Brian,
ich will 'nur' wissen wann es sinnvoll einen Dependency Injection Framework, wie LightCore zu verwenden.
Die abstrakte Klasse etc. ist mir alles klar. Macht Sinn.
Weniger klar ist warum es ein Nachteil ist, den new Operator von der Anwendung her aufzurufen.
Es wird ja instanziiert . Alle sagen besser in der Assembly. Keine Frage die haben bestimmt Recht. Ich will es nur 100%ig verstanden haben. Hat jemand eine gute Erklärung? Beispiel.
Am besten wäre halt ein einfaches Beispiel
A) Herkömmlich
B) C# händisch wie schon teils begonnen T result = (T)Activator.CreateInstance(foundType);
C) mit LightCore,
um eben zu sehen wo die Vorteile liegen, der Code evtl. kürzer wird etc.
Danke für Tipps und Grüße Oliver
-
Hallo Oliver,
Wenn Du eine Zeile wie:
IPerson person = new Person();
in deinem Code kompilierst, ist die Referenz person für immer und ewig an die konkrete Implementierung von Person gebunden. Du könntest - wie bereits gezeigt - diese Instazierung hinter einer Factory-Methode verbergen:
IPerson person = PersonFactory.Create("Max Müller"); // gibt Person, Employee, Manager zurück
und das wäre schon ein Tick besser, denn innerhalb von PersonFactory könntest Du jetzt z.B. nicht einfach eine Instanz von Person zurückgeben, sondern vielleicht eine davon abgeleitete Klasse wie Employee, oder Manager. PersonFactory.Create() könnte z.B. Max Müller in einer Datenbank nachschlagen, sehen dass er ein Angestellter ist und daraufhin eine Employee-Instanz zurückgeben (immer vorausgesetzt, dass Employee die Schnittstelle IPerson implementiert). Der Aufrufer-Code wäre dadurch nicht mehr direkt abhängig von einer bestimmten Implementation.
Natürlich muss die zurückgegeben Instanz irgendwie erstellt werden, entweder über new oder über Reflection (Activator.CreateInstance()). Wenn Du new verwenden willst, musst Du die Assembly referenzieren in der der zu instanzierende Typ steht. Das musst Du nicht tun, wenn Du die Instanz über Reflection erstellst.
Und eben deshalb verwenden DI-Container eher die Reflection-Methode. Der Sinn ist ja die Entkopplung des Consumer-Codes vom Implementierungs-Code. Dein Consumer-Code betrachtet den Container als Black-Box. Deshalb sagt der Consumer-Code zum Container: "Gib mir bitte irgendeine Instanz die IPerson implementiert". Und der Container antwortet: "Da bei mir als Implementationstyp für IPerson z.Z. die Klasse Employee registriert ist, werde ich gemäß der eingerichteten Auflösungsregeln für dich eine Instanz von Employee erstellen und sie dir zurückgeben."
Die Klasse Employee könnte nun in irgendeiner Assembly stehen von der die Aufrufer-Assembly keine Kenntnis hat. Was ich nicht weiß, mach mich nicht heiß. Ändert sich die Implementation von Employee, musst Du die aufrufende Assembly nicht neu kompilieren, Du kannst die neue Assembly einfach so verteilen und der DI-Container sorgt dafür, dass alle zufrieden sind. Will der Kunde B kein Employee verwenden sondern eher Instanzen von ContingentWorker, sei's drum, für der Aufrufercode ändert sich nichts. Neue Assembly eingespielt und weiter geht's.
Nun stell dir einmal vor, dass der Konstruktor von Person viele Argumente benötigen würde, z.B.
IPerson person = new Person(new SocialSecurityNumber(new UsCitizenshipInfo()), new PersonName());
wäre es nicht bequemer, statt diesen Konstruktor 100x überall im Code zu verwenden, einfach eine vorgefertigte Instanz vom Container zu verlangen?
IPerson person = Container.Resolve<IPerson>();
Der Container kennt die zu instanzierende Klasse, er kennt alle ihre Abhängigkeiten und kann dir die händische Arbeit ersparen.
Ich versuche hier zu vereinfachen. Wenn Du aber das ganze Bild sehen willst, lies Marc Seemans Buch Dependency Injection in .NET, Manning Publications, 2011.
Gruß
Marcel
-
Ich versuche hier zu vereinfachen. Wenn Du aber das ganze Bild sehen willst, lies Marc Seemans Buch Dependency Injection in .NET, Manning Publications, 2011.
Hallo Marcel,
ja das passt mal. Hätte halt noch konkret ein brauchbares Beispiel für LightCore gehabt.
So richtig gut erklärt, finde ich es nicht. LightCore
Ich denke fast besser ist das. http://www.edvsz.hs-osnabrueck.de/fileadmin/user/huelsmann/
Bessere Doku, etc.
Oder wie siehst Du es persönlich?
Grüße Oliver
-
Hallo Oliver,
"brauchbar" ist ein sehr dehnbarer Begriff.
Das MEF-Tutorial auf das Du verweist z.B., ist für einen allerersten Kontakt mit MEF "brauchbar", aber Du wirst anhand dieses Materials nicht wirklich verstehen, was MEF ist.
Viel eher bist Du am Ziel wenn Du dich durch die Artikelserie von Stefan Henneken durcharbeitest:
MEF Teil 1 - Grundlagen, Imports und Exports
MEF Teil 2 – Metadaten und Erstellungsrichtlinien
MEF Teil 3 – Lifecycle beeinflussen und überwachen
MEF Teil 4 – Vererbung mit Composable Parts
MEF Teil 5 – Composition und Recomposition
MEF Teil 6 – Constructor-Injection
MEF Teil 7 – Exportieren über eine Class Factory
MEF Teil 8 – Eigenen ExportProvider erstellen
MEF Teil 9 – Zugriff auf Composable Parts und Metadaten ohne Lazy<>
MEF Teil 10 – Parts über ExportProvider und App.config in AppDomain laden
MEF Teil 11 – Neuerungen unter .NET 4.5
MEF und LightCore sind zwei ziemlich verschiedene Konstrukte, weshalb man sie schlecht vergleichen kann.
Das Managed Extensibility Framework zum einen ist nur bedingt ein IoC-Container. Sein Hauptziel besteht darin, die eigene Anwendung um unbekannte plugin-ähnliche Module zur Laufzeit zu erweitern. MEF hat ausgefeilte Möglichkeiten, benötigte Parts zu suchen und obwohl Komposition mit MEF möglich ist, ist die Komposition nicht das Hauptanliegen von MEF.
LightCore auf der anderen Seite ist eher ein klassischer IoC-Container, das Autofac ähnelt. Die Features werden minimalistisch gehalten, damit eine gute Performanz erreicht wird. Anders als bei MEF sind die Typen mit denen man arbeitet i.d.R. bekannt. Es geht hier primär um dependecy injection und um Auflösen von Kopplung zwischen den Klassen. Zwar kann man auch in MEF Konstruktor-Injektion verwenden, aber in einem viel geringeren Umfang und mit weniger Optionen. Beispiele für die Verwendung findest Du auf der Seite des Autors, ich weiß nicht was daran unverständlich sein soll. Ansonsten verwende bitte die Suchmaschine deiner Wahl, es mangelt nicht an Beispielen zu LightCore.
Gruß
Marcel- Als Antwort markiert Oliver Stippe Dienstag, 3. September 2013 18:24
-
Ansonsten verwende bitte die Suchmaschine deiner Wahl, es mangelt nicht an Beispielen zu LightCore.
Hallo Marcel,
ja mit der Suche, das ist halt so eine Sache.
Irgendwie finde ich nichts brauchbares, halt viel wie meist. Lassen wir es einfach halt gut sein.Solltest Du selbst noch eine gute Seite wissen, YouTube etc. einfach noch antworten.
Viele Grüße Oliver
Das fand ich halt
http://www.mycsharp.de/wbb2/thread.php?postid=3637918
Via this blog i would like to inform all my friends i have started a series called as Learn c# and .NET in 60 days in youtube. YouTube