none
Dependency Injection -- Abhängigkeit Injektion RRS feed

  • 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 MEF

    In 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

    http://www.aspnetzone.de/blogs/peterbucher/archive/2010/12/05/Teil-1-_2D00_-Umkehrung-der-Kontrolle-erklaert-oder_5F00_Von-der-Fabrikmethode-zum-DI_5F00_Container.aspx

    Teil 1 - abstrakt --> alles klar

    http://www.aspnetzone.de/blogs/peterbucher/archive/2012/11/13/teil-2-umkehrung-der-kontrolle-erk-rt-oder-von-der-fabrikmethode-zum-di-container.aspx

    Teil 2 - weniger klar, verständlich


    Donnerstag, 29. August 2013 19:48

Antworten

Alle Antworten

  • Hallo Oliver,

    beim Durchlesen deines Textes ist mir spontan die Frage aufgekommen was du genau wissens willst....

    Freitag, 30. August 2013 08:02
  • 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.

    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.

    Gruß

    Marcel

    Freitag, 30. August 2013 10:14
    Moderator
  • 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


    Freitag, 30. August 2013 15:45
  • 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

    Freitag, 30. August 2013 17:08
    Moderator
  • 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/

    MEF

    Bessere Doku, etc.

    Oder wie siehst Du es persönlich?

    Grüße Oliver

    Sonntag, 1. September 2013 19:04
  • 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
    Montag, 2. September 2013 14:13
    Moderator
  •  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

    Suche

    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

    Dienstag, 3. September 2013 18:24