2010-01-05 12 views
36

Ich versuche Konstrukteurs MEF Attribut Injection, um herauszufinden. Ich habe keine Ahnung, wie ich es erzähle, um die Parameter des Konstruktors zu laden.MEF-Konstruktor Injection

Dies ist die Eigenschaft I zu laden bin versucht

[ImportMany(typeof(BUsers))] 
public IEnumerable<BUsers> LoadBUsers { get; set; } 

Hier ist der Code, den ich mit den Baugruppen zu importieren.

try 
{ 
    var catalog = new AggregateCatalog(); 
    catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly())); 
    catalog.Catalogs.Add(new DirectoryCatalog("DI")); 
    var container = new CompositionContainer(catalog); 
    container.ComposeParts(this); 
} 

Hier ist die Klasse I

[Serializable] 
[Export(typeof(BUsers))] 
public class EditProfile : BUsers 
{ 
    [ImportingConstructor] 
    public EditProfile(string Method, string Version) 
    {    
     Version = "2"; 
     Action = "Edit"; 
     TypeName = "EditProfile"; 
    } 

Antwort

53

Wenn Sie das ImportingConstructor Attribut verwenden, um die Parameter an den Konstruktor werden Importe zu laden bin versucht. Standardmäßig basiert das, was Sie importieren (der Vertragsname), auf dem Typ des Parameters oder der Eigenschaft, in den Sie importieren. In diesem Fall ist der Vertragstyp für beide Importe eine Zeichenfolge und es besteht kein echter Unterschied zwischen dem ersten und dem zweiten Parameter.

Es sieht aus wie Sie versuchen, Importe zu verwenden, um Konfigurationswerte zu liefern, die nicht unbedingt ist, was es für entworfen wurde. Um es zu tun, was Sie wollen, sollten Sie den Vertrag Name für jeden der Parameter außer Kraft setzen, wie folgt aus:

[ImportingConstructor] 
public EditProfile([Import("Method")] string Method, [Import("Version")] string Version) 
{ } 

Dann brauchen Sie Exporte für Methode und Version in Ihrem Container. Eine Möglichkeit, dies zu tun ist, nur um sie direkt hinzuzufügen:

var container = new CompositionContainer(catalog); 
container.ComposeExportedValue("Method", "MethodValue"); 
container.ComposeExportedValue("Version", "2.0"); 
container.ComposeParts(this); 

(Beachten Sie, dass ComposeExportedValue ist eigentlich eine Erweiterung Methode auf der statischen AttributedModelServices Klasse definiert.)

Wenn Sie diese Werte von einer Konfiguration lesen möchten Datei von einer Art, könnten Sie Ihren eigenen Export-Provider erstellen, der die Konfiguration liest und die Werte als Exporte an den Container zur Verfügung stellt.

Eine alternative Möglichkeit, dies zu handhaben wäre, nur eine Schnittstelle zu importieren, die den Zugriff auf die Konfigurationswert von Namen und erhalten Sie die Werte, die Sie benötigen, aus dem Körper des Konstrukteurs zur Verfügung stellt.

+0

Ich habe gerade den neuen CodePlex heruntergeladen. Die Methode von ComposeExportedValue() befindet sich nicht in der Klasse von CompositionContainer. Wo ist es? –

+0

Ich denke, ich habe die Methode gefunden. Es befindet sich in der Klasse von AttributedModelServices, in der die Methode als erweiterte Methode für die Klasse CompositionContainer definiert ist. –

+1

@ David.Chu.ca Ja, ComposeExportedValue ist eine Erweiterungsmethode für die AttributedModelServices-Klasse. –

23

Ich mag Daniel-Lösung; Allerdings sehe ich nur die enge Kopplung von Parameternamen zwischen dem Akteur (der CompopositionContrainer() erstellt) und dem Exportteil mit [ImportingConstructor] für das angepasste CTOR. Zum Beispiel, "Methode" hat zwei an beiden Orten übereinstimmen. Es ist schwierig, den Exportteil beizubehalten, wenn sich der Akteur und der Exportteil in unterschiedlichen Projekten befinden.

Wenn es möglich ist, würde ich die zweite CTOR zum Export Teil Klasse hinzuzufügen. Zum Beispiel: zwei Eigenschaften der Methode und Version:

[Export(typeof(BUsers))] 
public class EditProfile : BUsers 
{ 
    [ImportingConstructor] 
    public EditProfile(EditProfileParameters ctorPars) 
    : this(ctorPars.Method, ctorPars.Version) {} 

    public EditProfile(string Method, string Version) 
    { 
     Version = "2"; 
     Action = "Edit"; 
     TypeName = "EditProfile"; 
    } 

Die Klasse der EditProfileParameters sollte einfach sein

[Export] 
public class EditProfileParameters{ 
    public string Method { get; set; } 
    public string Version { get; set; } 
} 

Der entscheidende Punkt ist der Export Attribut der Klasse hinzuzufügen. Dann sollte MEF in der Lage sein, diese Klasse dem Parameter des CTOR von EditProfile zuzuordnen.

Hier ist beispielsweise die Exportteil Container hinzuzufügen:

var container = new CompositionContainer(catalog); 
var instance1 = new EditProfileParameters(); 
// set property values from config or other resources 
container.ComposeExportedValue(instance1); 
container.ComposeParts(this); 
0

Obwohl spät, um das Spiel, hier ist ein weiterer Ansatz, der eine weniger bekannte Funktion von MEF nutzt: Immobilien Exporte

public class ObjectMother 
{ 
    [Export] 
    public static EditProfile DefaultEditProfile 
    { 
     get 
     { 
      var method = ConfigurationManager.AppSettings["method"]; 
      var version = ConfigurationManager.AppSettings["version"]; 

      return new EditProfile(method,version); 
     } 
    } 
} 

Für ObjectMother sind keine Verwendungen erforderlich, damit dies funktioniert und für EditProfile sind keine Attribute erforderlich.

+0

Schöne Funktion, aber was ist, wenn 'EditProfile' irgendwelche Importe enthält? In diesem Fall müssen Sie 'SatisfyImportsOnce' für den Container aufrufen. Das tut weh. Derzeit habe ich keine echte Lösung für dieses Problem. –

+0

In diesem Fall erstellen wir eine Factory, die Ihr EditProfile manuell instanziiert. Wenn EditProfile zusätzliche Abhängigkeiten im Konstruktor erfordert, können Sie diese Abhängigkeiten immer über einen ImportConstructor in die Factory importieren. Ich sollte darauf hinweisen, dass, wenn Sie zusätzliche Abhängigkeiten zu EditProfile hinzufügen, dies der einzige Verweis in Ihrer Anwendung auf diesen Konstruktor ist und Sie Kompilierungszeitfehler erhalten. Es ist ein fairer Handel, IMHO. – bryanbcook