Wie könnte die Abhängigkeitsinjektion in die Sprache integriert werden? [geschlossen]

10

Ich habe ein wenig darüber nachgedacht, wie die Abhängigkeitsinjektion besser direkt in eine C # -ähnliche Sprache integriert werden kann. Ich habe eine mögliche Lösung gefunden, zu der ich gerne Ihre Meinung hören würde. Ich habe nicht viele Frameworks für die Abhängigkeitsinjektion verwendet, daher kann es sein, dass ich etwas übersehen habe

Auf jeden Fall besteht die Idee darin, Eigenschaften mithilfe eines Schlüsselworts als "injizierbar" deklarieren zu können. Wenn ein Objekt instanziiert wird und diese Eigenschaft nicht über den Konstruktor oder den Objektinitialisierer initialisiert wird, fordert es eine Instanz dieses Eigenschaftstyps von einem globalen Dienst an.

In ähnlicher Weise registrieren Sie Handler für verschiedene Typen für diesen Dienst, damit Sie den injizierten Eigenschaftstyp instanziieren können.

Der Vorteil dieser Art von Architektur IMO ist, dass sie ziemlich flexibel und einfach zu bedienen ist. Der Nachteil ist, dass das Aufrufen des Singletons jedes Mal, wenn Sie eine Klasse mit Injection initiieren, mit einem gewissen Aufwand verbunden sein kann.

Andererseits ist dies nur ein Problem für Klassen, die in einer Hochleistungslösung häufig instanziiert werden, sodass es kein großes Problem sein sollte. Vielleicht könnten Sie in diesen Fällen eine Art Fabrik benutzen.

Gedanken, Probleme, Fragen, bessere Ideen?

Code

public class SomeClass
{

  public SomeClass()
  {
     //implicit behavior if Animal is not set in constructor or initializer
    this.Animal =  GlobalInjector.Get(this,typeof(Mammal))

  }

  public injectable Mammal Animal  
  {
   get;
   set;
  }
}


 GlobalInjector.Register(typeof(Mammal), () => return new Mammal(someParameter));
Homde
quelle
Könnten Sie ein Pseudocode-Beispiel für diejenigen von uns geben, die mit DI nicht vertraut sind? PS. Vielleicht können Sie meine Frage zu DI auch beantworten? :)
Steven
2
Ich bin mir nicht sicher, ob ich es verstehe. Sie können all das mit einem globalen DI-Container und einem '[Injectable]' - Attribut anstelle eines Schlüsselworts erhalten, oder?
Nikie
Hallo, ich habe versucht, ein bisschen über DI auf Ihre Frage zu schreiben, bin mir aber nicht sicher, ob sie sie beantwortet
Homde
Nikie: Ja sicher, ich denke, Sie könnten den eigentlichen Mechanismus auf verschiedene Arten implementieren. Ich bin mehr daran interessiert, ob die zugrunde liegende Logik solide ist
Homde
Was unterscheidet sich also von diesem und dem vorhandenen IoC außer Ihrem zusätzlichen Keyword?
Matthew Whited

Antworten:

7

Es gibt Dinge, die in Sprachen gehören, und Dinge, die nicht dazu gehören. Vor langer Zeit hat C erkannt, dass IO nicht in die Sprache gehört, da es außerhalb des Rechenmodells liegt und mit Funktionsbibliotheken implementiert werden kann.

Abhängigkeitsinjektion ist so. Es ist außerhalb der Sprache und kann mit geeigneten Frameworks implementiert werden.

Eines der Probleme mit modernen Sprachen ist, dass sie versuchen, zu viel zu tun. Schließlich brechen diese Sprachen unter ihrem eigenen Gewicht zusammen, während Programmierer zu einfacheren Sprachen fliehen.

Onkel Bob.
quelle
Ich stimme theoretisch zu, dass man keine Sprache haben kann, in der jede Funktion ein Merkmal der Sprache ist, ohne dass sie aufgebläht ist. Es gibt jedoch immer Platz für neue höhere Abstraktionen, die uns helfen, besseren Code zu schreiben. Vielleicht ist die Abhängigkeitsinjektion an sich nicht das Problem, das gelöst werden muss, sondern das Problem, das darin angesprochen wird, nämlich eine Möglichkeit, es uns zu erleichtern, Abhängigkeiten zu reduzieren. Dies ist jedoch möglicherweise nicht der beste Weg, dies zu tun :)
Homde
5

Es wird nicht benötigt

Eines der Dinge, die mir an den besten DI-Frameworks, die ich verwendet habe, am besten gefallen, ist, dass der Konfigurationscode der obersten Ebene der einzige Teil Ihres Codes ist, der über DI Bescheid wissen muss. Die automatische Verkabelung erfolgt auf Container- und Konfigurations- / "Modul-Lade" -Ebene, und Ihr Anwendungscode kann dies völlig vergessen.

Dies bedeutet keine Attribute, keine magischen Zeichenketten, keine Konvention. Jeder Code weiß nur, dass er Code in seinem Konstruktor akzeptiert (/ properties / Methods), und das ist alles.

Bei einem solchen Design müssen Sie die Sprache überhaupt nicht ändern, um Dependency Injection zu unterstützen.

Es ist möglicherweise gefährlich

Das, was ich an einem sprachintegrierten Abhängigkeitsinjektionssystem am meisten fürchte, ist, dass es eine Barriere gegen jede andere Implementierung bilden würde, sich aber wahrscheinlich in gewisser Hinsicht in eine Ecke streichen würde.

Einige Möglichkeiten, wie es sich in eine Ecke malen könnte:

  • Unterstützt nur XML-basierte Konfiguration oder nur Code-basierte Konfiguration
  • Das Factory-Entwurfsmuster kann nicht sauber unterstützt werden (nicht nur vorübergehende Komponenten: zur Laufzeit generierte Komponenten)
  • Irgendwie habe ich meinen Code geändert, sodass ich gezwungen war, die Abhängigkeitsinjektion zu verwenden, und konnte meine Klasse nicht einfach für Komponententests instanziieren
  • Benutzerdefinierte Lebenszyklen werden nicht unterstützt
  • Nicht erweiterbar
  • Nicht austauschbar in Fällen, in denen ich größere Anpassungen benötige
  • Auf eine Weise kaputt zu sein, die wir noch nicht verstehen, weil wir .Net-Benutzer DI nicht lange genug verwenden, um die Fallstricke zu kennen
Merlyn Morgan-Graham
quelle
4

Haben Sie das mit .NET 4 gelieferte Managed Extensibility Framework gesehen ? Hier ist ein Artikel, den ich mit einigen Beispielen geschrieben habe. Grundsätzlich handelt es sich um eine in .NET integrierte Form der Abhängigkeitsinjektion mit den zusätzlichen Funktionen zur Erkennbarkeit zur Laufzeit.

Eigenschaftsinjektionen sehen folgendermaßen aus:

class Program
{
    [Import]
    public IMessageSender MessageSender { get; set; }
}

Konstruktorinjektionen sehen folgendermaßen aus:

class Program
{
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
    ...
    }
}

Sie können Felder importieren, optional importieren, Sammlungen von Diensten importieren, einschließlich des verzögerten Imports mit Metadaten, damit Sie nach einem geeigneten Dienst zum Instanziieren suchen können. Sie können zur Laufzeit sogar erneut importieren, um nach neuen Erweiterungen zu suchen.

Scott Whitlock
quelle
Während MEF für Plugin-Sachen wirklich cool ist, glaube ich nicht, dass ich es als allgemeinen DI-Mechanismus verwenden
möchte
1
@MKO - Können Sie näher erläutern, was fehlt? Mir sind alle Artikel bekannt, in denen Glenn Block Rennen fährt, um den Leuten zu versichern, dass MEF nicht alle DI-Frameworks ersetzen will, aber wenn man sich die Details ansieht, ist es offensichtlich, dass dies eher eine politische Aussage als irgendetwas anderes ist. Wenn Sie jedoch eine gute Liste von Funktionen angeben können, die MEF im Vergleich zu anderen DI-Frameworks fehlen, hilft dies den Menschen, eine fundierte Entscheidung zu treffen. Außerdem geht es um DI-Frameworks in C #, und MEF ist eindeutig ein DI-Container im .NET-Framework.
Scott Whitlock
2
  1. Sie beschreiben den Konfigurationsmechanismus nicht wirklich, was meiner Meinung nach das schwierige Stück ist. Wie lässt man den gesamten Code, der in einem Thread ausgeführt wird, die DB-Verbindung A und den gesamten Code in der anderen Thread-Verbindung B verwenden? Wie blockieren Sie die Injektion einer bestimmten Ressource, weil der aktuell angemeldete Benutzer nicht darauf zugreifen darf?
  2. Verwenden Sie keinen globalen Injektor. Verwenden Sie überhaupt keine globalen Variablen, oder Sie können auch globale Variablen verwenden. Nein, die Verwendung von OOP-speak wie Singleton oder "static" anstelle von global ändert nichts an ihrer globalen Natur.
  3. Betrachten Sie einen Container mit dynamischem Gültigkeitsbereich. Während lexikalisches Scoping zu Recht gegen dynamisches Scoping gewonnen hat, glaube ich, dass dynamisches Scoping einen guten Ersatz für globales Scoping darstellen würde. Differenzielle Vererbung wäre eine nette Implementierung (wie bei der prototypbasierten Vererbung).
  4. Ich glaube, dass ein sprachgebundener DI-Mechanismus wirklich einfach sein sollte, nichts von dem unternehmerischen Zeug, das in C # und Java die Norm ist. Ein dynamischer Scoping-Mechanismus mit einer einfachen Konfigurationsebene könnte den Trick tun. Unternehmenslösungen könnten von Dritten überlagert werden.
Waquo
quelle