2011-01-10 9 views
13

ich folgende ExportMetaData Attribut auf meiner Klasse gesetzt:Wie legen Sie ExportMetaData mit mehreren Werten sowie einzelnes w/benutzerdefiniertes Attribut fest?

[Export(typeof(IDocumentViewer))] 
    [ExportMetadata("Name", "MyViewer")] 
    [ExportMetadata("SupportsEditing", true)] 
    [ExportMetadata("Formats", DocFormat.DOC, IsMultiple = true)] 
    [ExportMetadata("Formats", DocFormat.DOCX, IsMultiple = true)] 
    [ExportMetadata("Formats", DocFormat.RTF, IsMultiple = true)] 

Ich habe auch eine unterstützende Schnittstelle:

public interface IDocumentViewerMetaData { 
    /// <summary> 
    /// Gets the format. 
    /// </summary> 
    /// <value>The format.</value> 
    IEnumerable<DocFormat> Formats { get; } 
    /// <summary> 
    /// Gets the name of the viewer 
    /// </summary> 
    /// <value>The name.</value> 
    string Name { get; } 
    /// <summary> 
    /// Gets a value indicating whether this viewer supports editing 
    /// </summary> 
    /// <value><c>true</c> if [supports editing]; otherwise, <c>false</c>.</value> 
    bool SupportsEditing { get; } 
    } 

Und meinen ImportMany natürlich:

[ImportMany(typeof(IDocumentViewer))] 
public IEnumerable<Lazy<IDocumentViewer, IDocumentViewerMetaData>> _viewers { get; set; } 

Was würde ich Sie verwenden eine stark typisierte Attributklasse, anstatt das ExportMetaData-Attribut zu verwenden. Ich habe keinen Weg gefunden, dies zu tun, während ich auch einzelne Werte unterstütze (Name, SupportsEditing, im obigen Beispiel).

ich etwas ähnlich der folgenden Envision tun (oder was auch immer, wie am besten vorgeschlagen wird):

[Export(typeof(IDocumentViewer))] 
[DocumentViewerMetadata(Name = "MyViewer")] 
[DocumentViewerMetadata(SupportsEditing = true)] 
[DocumentViewerMetadata(Format = DocFormat.DOC)] 
[DocumentViewerMetadata(Format = DocFormat.DOCX)] 

ich ziemlich sicher bin, dass es einen Weg gibt, dies zu tun, ich habe einfach nicht den richtigen Weg gefunden zu verbinde die Punkte. :)

Antwort

17

Sie können die ExportAttribute mit Ihrer eigenen Implementierung Unterklasse, und schmücken sie mit einem MetadataAttribute MEF zu ermöglichen, um seine Eigenschaften zu verwenden, um die Metadaten-Proxy zu projizieren es während Zusammensetzung verwendet:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property), 
MetadataAttribute] 
public class ExportDocumentViewerAttribute : ExportAttribute, IDocumentViewerMetadata 
{ 
    public ExportDocumentViewer(string name, bool supportsEditing, params DocFormat[] formats) 
    : base(typeof(IDocumentViewer)) 
    { 
    if (string.IsNullOrEmpty(name)) 
     throw new ArgumentException("Export requires a name", "name"); 

    Name = name; 
    SupportsEditing = supportsEditing; 
    Formats = formats ?? Enumerable.Empty<DocFormat>(); 
    } 

    public string Name { get; private set; } 

    public bool SupportsEditing { get; private set; } 

    public IEnumerable<DocFormat> Formats { get; private set; } 
} 

[ExportDocumentViewer("Word", true, DocFormat.DOC, DocFormat.DOCX)] 
public WordDocumentViewer : IDocumentViewer 
{ 
    // Stuff 
} 

Hinweis Sie muss nicht wirklich mit Ihrem IDocumentViewerMetadata Vertrag schmücken, wie MEF es projizieren wird, ich bevorzuge es nur, so dass ich weiß, wenn ich Änderungen am Metadatenvertrag mache, dass mein benutzerdefiniertes Exportattribut übereinstimmt.

+0

Matthew - danke !! Ich verstehe die Änderungen, die Sie vorgenommen haben, und bevorzuge sie tatsächlich - weniger Attribute, die auf die Klassen angewendet werden, sowie einige zusätzliche Typ-Sicherheit (Implementierung der Schnittstelle). Auch jetzt weiß ich, was ich vermisst habe, soweit es möglich ist, mehrere Gegenstände zu übergeben .. params []! Ich war so nah an deiner Lösung, aber habe diesen kleinen Punkt verpasst. Vielen Dank für Ihre ausgezeichnete Antwort. –