2012-09-05 8 views
15

Ich habe ein Projekt, in dem das Ninject als IoC-Container verwendet wird. Meine Sorge ist, dass viele Klassen eine solche Art von Konstrukteuren haben:Lazy Dependency Injection

[Inject] 
public HomeController(
    UserManager userManager, RoleManager roleManager, BlahblahManager blahblahManager) { 
    _userManager = userManager; 
    _roleManager = roleManager; 
    _blahblahManager = blahblahManager; 
} 

Was passiert, wenn ich will nicht auf einmal alle Instanzen dieser Klassen haben?

Die Art und Weise, wenn all diese Klassen von Lazy<T> gewickelt und an den Konstruktor übergeben werden, ist nicht genau das, was ich brauche. Die T Instanzen sind noch nicht erstellt, aber Lazy<T> Instanzen sind bereits im Speicher gespeichert.

Mein Kollege schlägt mir vor, Factory-Muster zu verwenden, um die Kontrolle über alle Instanziierungen zu haben, aber ich bin mir nicht sicher, ob IoC einen so großen Design-Bug hat.

Gibt es einen Workaround für diese Situation oder IoC haben wirklich so großen Defekt in seinem Design? Vielleicht sollte ich einen anderen IoC-Container verwenden?

Irgendwelche Vorschläge?

+0

Was ist eigentlich dein Problem? Warum willst du diese Instanzen nicht? –

+2

Ich möchte UserManager während der Arbeit des Controllers, aber RoleManager wird nicht benötigt und umgekehrt. Wenn Sie über die Lazy Instanzen sprechen, dann ist das keine große Sache, sie im Speicher zu haben, aber ist das der einzige Weg? – xwrs

+1

Warum ist es eine große Sache für 'UserManager' und' RoleManager'? Ihre Konstrukteure sollten ohnehin keine schwere Arbeit verrichten. –

Antwort

36

Scheint mir, dass Sie premature optimization tun: tun Sie es nicht.

Die Ersteller Ihrer Dienste sollten nothing more als Speichern der Abhängigkeiten, die es in privaten Feldern dauert, tun. In diesem Fall ist die Erstellung eines solchen Objekts wirklich gering. Vergessen Sie nicht, dass die Erstellung von Objekten in .NET sehr schnell ist. In den meisten Fällen ist es aus Performanceperspektive egal, ob diese Abhängigkeiten injiziert werden oder nicht. Besonders im Vergleich zur Anzahl der Objekte spuckt der Rest Ihrer Anwendung (und die von Ihnen verwendeten Frameworks) aus. Die tatsächlichen Kosten entstehen, wenn Sie beginnen, Webdienste, Datenbanken oder das Dateisystem (oder I/O im Allgemeinen) zu verwenden, weil sie eine viel größere Verzögerung verursachen.

Wenn die Schöpfung wirklich teuer ist, sollten Sie verstecken normalerweise die Schaffung hinter einem Virtual Proxy stattdessen ein Lazy<T> in jedem Verbraucher der Injektion, da dieser Code gemeinsame Anwendung ermöglicht die Tatsache, zu bleiben nicht bewusst, dass es ein Mechanismus ist, die Schöpfung zu verzögern (Sowohl Ihr Anwendungscode als auch Ihr Testcode werden dabei immer komplexer).

Kapitel 6 von Dependency Injection in .NET, second edition enthält eine ausführlichere Diskussion über Lazy und Virtual Proxies.

jedoch ein Lazy<T> verbraucht nur 20 Bytes des Speichers (und eine andere für seine 24 bytes gewickelten Func<T>, einen 32-Bit-Prozess unter der Annahme) und die Erzeugung einer Instanz Lazy<T> praktisch frei. Sie müssen sich also keine Gedanken darüber machen, es sei denn, Sie befinden sich in einer Umgebung mit sehr engen Speicherbeschränkungen.

Und wenn Speicherverbrauch ein Problem ist, versuchen Sie, Dienste mit einer Lebensdauer zu registrieren, die größer als transient ist. Sie können eine pro Anfrage, per Web-Anfrage oder Singleton machen. Ich würde sogar sagen, dass Sie in einer Umgebung, in der das Erstellen neuer Objekte ein Problem darstellt, wahrscheinlich nur Singleton-Dienste verwenden sollten (aber es ist unwahrscheinlich, dass Sie an einer solchen Umgebung arbeiten, da Sie eine Web-App erstellen). .

Beachten Sie, dass Ninject eine der langsameren DI-Bibliotheken für .NET ist. Wenn das dich beunruhigt, switch to a faster container. Einige Container weisen eine Leistung auf, bei der Objektgrafiken von Hand neu erstellt werden. aber auf alle Fälle, Profil dies, viele Entwickler wechseln DI-Bibliotheken aus den falschen Gründen.

Beachten Sie, dass die Verwendung von Lazy<T> als Abhängigkeit leaky abstraction (eine Verletzung der Dependency Inversion Principle) ist. Bitte lesen Sie this answer für weitere Informationen.

+0

Danke. Du hast mein Verständnis der Situation klarer gemacht. – xwrs

+0

Ich glaube nicht, dass es eine vorzeitige Optimierung ist, mit diesem Argument scheint es, dass Lazy nie benötigt wird. Die Erstellung eines Objekts ist nicht schwer, aber Sie wissen nicht, wie viele Objekte es in seinem Konstruktor erzeugt. Und eine entfernte Ressource öffnen, die nicht verwendet werden kann. –

0

New

Steven ist richtig zu sagen, dass dies wie vorzeitige Optimierung aussieht. Die Konstruktion dieser Objekte ist sehr schnell und ist meist nie der Flaschenhals.

Die Verwendung von Lazy zum Ausdruck einer Abhängigkeit, die Sie nicht sofort benötigen, ist jedoch ein übliches Muster in Dependency Injection-Frameworks. Actofac ist ein solcher Container, der Unterstützung für various wrapping types eingebaut hat. Ich bin mir sicher, dass es auch eine Erweiterung für Ninject gibt, vielleicht schau dir diese an, Ninject Lazy.

+1

Die Tatsache, dass DI-Container Unterstützung für Lazy haben, macht es nicht richtig, Ihren Anwendungscode von einer Lazy -Abhängigkeit abhängig zu machen. Viele DI-Container unterstützen Funktionen, die keine Best Practices fördern. Lazy ist aus Sicht der Dependency Injection eine undichte Abstraktion. Bitte lesen [this] (https://stackoverflow.com/a/21724609/264697) für eine Erklärung, warum Lazy Lecks. – Steven