简体   繁体   中英

How to export same metadata multiple times on same class

Given an exported class with an associated metadata view, is it possible to export the same metadata view multiple times into effectively a single metadata object? Below is an example of why I would want to do this, ie the metadata being exported is multiple lists of strings, which logically makes more sense as multiple attributes:

[ExportHandledNamespace("System", "Data")]
[ExportHandledNamespace("System", "Core")]    
public class NamespaceHandler : INamespaceHandler { }

public interface INamespaceHandlerMetadata
{
    string[] HandledNamespaces { get; }
}

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class ExportHandledNamespaceAttribute : ExportAttribute, INamespaceHandlerMetadata
{
    // In my use case, NamespaceHandler would be in a plugin assembly 
    // and I don't want them using this delimiter themselves
    private string _namespaceDelimiter = ".";

    public string[] HandledNamespaces { get; }

    public ExportHandledNamespaceAttribute(params string[] namespaceIdentifiers) 
           : base(typeof(INamespaceHandler))
    {
        string namespace = String.Join(_namespaceDelimiter, namespaceIdentifiers);
        // Somehow add this to an existing metadata view's HandledNamespaces
    }
}

This is how I would want to use such an export:

public void ExampleUsageMethod() 
{
    var handler = mefContainer.GetExports<INamespaceHandler, INamespaceHandlerMetadata>().First();
    string[] handledNamespaces = handler.Metadata.HandledNamespaces;
}

I solved my issue by splitting ExportHandledNamespaceAttribute into a single Export on INamespaceHandler and a MetadataAttribute on the namespace identifiers with a custom metadata view, as below. The trick here is to get the contracts between the import expected by INamespaceHandlerMetadata and the export provided by HandlesNamespaceAttribute exactly right. Let me know if I can improve/clarify this answer any:

[Export(typeof(INamespaceHandler))]
[HandlesNamespace("System", "Data")]
[HandlesNamespace("System", "Core")]    
public class NamespaceHandler : INamespaceHandler { }

[MetadataViewImplementation(typeof(NamespaceHandlerMetadata))]
public interface INamespaceHandlerMetadata
{
    string[] HandledNamespaces { get; set; }
}

public class NamespaceHandlerMetadata : INamespaceHandlerMetadata 
{
    string[] HandledNamespaces { get; set; }

    public NamespaceHandlerMetadata(IDictionary<string, object> exportedMetadata)
    {
        HandledNamespaces = exportedMetadata[nameof(HandledNamespaces)];
    }
}

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class HandlesNamespaceAttribute : Attribute
{
    private string _namespaceDelimiter = ".";

    // Because the attribute is marked AllowMultiple = true, this will get exported 
    // as a string[], despite it appearing to only be set once in the constructor below
    public string HandledNamespaces { get; }

    public ExportHandledNamespaceAttribute(params string[] namespaceIdentifiers) 
           : base(typeof(INamespaceHandler))
    {
        string namespace = String.Join(_namespaceDelimiter, namespaceIdentifiers);
        HandledNamespaces = namespace;
    }
}

The example usage is the same as in the question, querying for an export of Lazy<INamespaceHandler, INamespaceHandlerMetadata> and getting its HandledNamespaces . But another example use case is below, using ImportMany

public class NamespaceHandlerManager, IPartImportsSatisfiedNotification
{
    [ImportMany]
    public IEnumerable<Lazy<INamespaceHandler, INamespaceHandlerMetadata>> NamespaceHandlers { get; set; }

    public NamespaceHandlerManager() { }

    public void OnImportsSatisfied()
    {
        // NamespaceHandlers will be populated with the exports from any 
        // loaded assemblies by this point, do what you want with it
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM