如何在同一个类上多次导出相同的元数据

时间:2018-03-07 17:00:29

标签: c# .net mef

如果导出的类具有关联的元数据视图,是否可以将相同的元数据视图多次导出到单个元数据对象中?下面是我想要这样做的一个例子,即导出的元数据是多个字符串列表,这在逻辑上更有意义作为多个属性:

[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
    }
}

这就是我想要使用这种导出的方式:

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

1 个答案:

答案 0 :(得分:0)

我通过使用自定义元数据视图将ExportHandledNamespaceAttribute分割为Export上的INamespaceHandler和命名空间标识符上的MetadataAttribute来解决了我的问题,如下所示。这里的诀窍是获得INamespaceHandlerMetadata期望的导入与HandlesNamespaceAttribute提供的导出之间的合同完全正确。如果我可以改进/澄清这个答案,请告诉我:

[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;
    }
}

示例用法与问题中的相同,查询导出Lazy<INamespaceHandler, INamespaceHandlerMetadata>并获取其HandledNamespaces。但是下面的另一个示例用例是使用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
    }
}
相关问题