2016-04-16 8 views
0

Ich habe eine Schnittstelle, lassen Sie uns sagen, es ist IDrawingTool. Ich habe mehrere Klassen implementieren diese Schnittstelle, sagen wir PencilTool, PenTool, YellowMarkerTool, etc. Ich bin in der Regel binden mehr als eine dieser Klassen in Ninject, und ich immer Zugriff auf IDrawingTool Instanzen durch den Aufruf kernel.GetAll<IDrawingTool>. So weit, ist es gut.Erstellen eines benutzerdefinierten Ninject-Provider für mehrere Typen, die die gleiche Schnittstelle implementieren

Nun möchte ich eine neue IDrawingTool Implementierung, ConfigurableBrushTool, die auf viele verschiedene Arten konfiguriert werden kann (sagen wir Pinselfarbe, Pinsel Dicke, etc).

Ich möchte in der Lage sein, eine Art von "Fabrik"/"Anbieter" zu haben, die mich mehrere IDrawingTool s (d. H. Mehrere ConfigurableBrushTool s mit verschiedenen Konfigurationen) injizieren können. Das heißt, ich möchte so etwas wie die folgenden in der Lage sein zu tun:

kernel.Bind<IDrawingTool>.To<PencilTool>(); 
kernel.Bind<IDrawingTool>.To<PenTool>(); 
kernel.Bind<IDrawingTool>.ToTypeProvider<ConfigurableBrushToolProvider>(); 
//...where ConfigurableBrushToolProvider reads e.g. 50 different 
//brush configurations (color, thickness, etc) from the database/file/network/whatever 
//and binds 50 different ConfigurableBrushTool instances. 
//Of course, .ToTypeProvider() doesn't really exist :) 

//Later on: 
var tools = kernel.GetAll<IDrawingTool>(); //Should return pencil, pen and all 50 brushes 

Ich habe nicht in der Lage gewesen, einen Weg zu finden, diese mit Ninject passieren.

Ich habe bei der Implementierung IProvider/Provider<T> untersucht, aber ich kann nur eine Instanz des von mir bereitgestellten Typs zurückgeben. Es gibt keine Möglichkeit, mehrere Instanzen in großen Mengen zurückzugeben.

ich auch bei IMissingBindingResolver geschaut habe, und es ist ganz in der Nähe, was ich brauche: Wenn ich so einen Resolver für IDrawingTool schaffen, ich bin in der Lage für ConfigurableBrushTool s mehr mehrere Bindungen zurückzukehren. Es funktioniert jedoch nur, wenn die Bindung fehlt (d. H. Wenn es keine anderen IDrawingTool Bindungen gibt). Sobald ich meine PenTool und PencilTool Bindungen hinzufügen, ist die Bindung für IDrawingTool nicht mehr "fehlend" und so wird meine benutzerdefinierte Resolver nicht mehr aufgerufen.

Gibt es eine Möglichkeit, mein Szenario passieren zu lassen? I.e. Wie kann ich eine Schnittstelle an (1) spezifische Typen binden, die die Schnittstelle implementieren, und (2) einen "factory"/"provider" von vielen Instanzen, die die Schnittstelle implementieren, so dass GetAll alle Bindungen zurückgibt, beides (1) und 2)?

Antwort

1

Zunächst einmal sieht es so aus, als ob es keine OOTB Funktion gibt, um mehrere Bindungen von einem Bindungssatz in Modul zu machen (zumindest habe ich keinen offensichtlichen gefunden).
Zweitens, ich habe es geschafft, einige PoC mit benutzerdefinierten Kernel zu erstellen, mit dem Sie One-to-many Bindung mit einem .Bind.To Aufruf erstellen können. Es basiert auf dem Überschreiben IKernel.GetBindings(..) Methode und finden alle Bindungen mit speziellen Parameter. Dann können wir sie entfernen, indem wir die Menge der erzeugten benutzerdefinierten ersetzen.
Ich denke jedoch, dass eine solche Logik großen Einfluss auf die Leistung haben wird, wenn nicht sorgfältig optimiert (was nicht fürgetan wird) und sollte es nur dann zur Produktion machen, wenn es wirklich benötigt wird. Diese PoC finden Sie here.
Für mich ist es viel besser Ansatz Refactoring vorhandenen Code zu injizieren eine Factory-Return-Array erstellt on-the-fly.

+0

Danke! Schade, dass es keine vorgefertigte Lösung gibt ... Ich schätze die Arbeit, die Sie hier geleistet haben, trotz der Perfomance, dass Ihr Code genau das erreicht, was ich brauche (obwohl ich realistischerweise wahrscheinlich das Refactoring wählen werde) Ansatz), aber in jedem Fall ist Bounty deins. –

+0

Danke, Eugene, hoffe dieses Beispiel würde dir sowieso helfen, die Möglichkeiten von Ninject zu verstehen. –

0

Wie über eine eigene Sammlung (Umgehen Multi-Injektion) Bindung wie:

public interface IToolList : IReadOnlyList<IDrawingTool> {} 

und haben es Implementierung zurückgeben beide gebunden Werkzeuge und die, die „geschaffen“ aus der Datenbank, so etwas wie:

public class ToolList : List<IDrawingTool>, IToolList 
{ 
    public ToolList(IDrawingTool[] boundTools,... otherDependencies) 
    { 
     ... create all tools here 
    } 
} 
+0

Es gibt eine große, bestehende Codebase, die GetAll bereits an einer Reihe von Orten verwendet - ich würde lieber nicht alle diese Orte ändern, um IToolList zu verwenden (auch ein anderer Entwickler wird das im Special nicht wissen) Bei IDrawingTool müssen Sie auf IToolList zugreifen und nicht nur auf den Standard GetAll). Um es klar zu sagen, mein wirklicher Anwendungsfall ist nicht das Zeichnen von Werkzeugen, sondern komplexe Geschäftsobjekte:), es gibt noch viel mehr Dinge, Ninject-Ed. Deine Antwort funktioniert als Workaround, aber ich würde gerne wissen, ob Ninject genau das tut, was ich brauche. –

Verwandte Themen