为什么MEF2不将元数据属性应用于所有零件导出?

时间:2016-10-04 08:45:11

标签: c# mef mef2

我正在尝试将基于.NET Framework的应用程序集合移植到.NET Core,作为此过程的一部分,我需要从使用MEF1切换到MEF2。我在围绕与MEF2有关的问题时遇到了很多困难(尽管我发现this post真的很有帮助),但我最近偶然发现其中一个我曾经有过的原因

特别是,我有许多使用自定义ExportAttribute导出元数据的类,我想将它们全部导入到另一个类中,并根据此元数据对其进行过滤。这在MEF1中都运行良好,但在MEF2中,我遇到了诸如“ x 的导出元数据缺失且没有提供默认值”等问题。“

更具体地说,我注释了我的导出类,如下所示:

[Export(typeof(IClientRequestProcessor<RelaySystemModel>))]
[TargetDevice("<<Foo>>")]
internal class RelaySystemClientRequestProcessor : IClientRequestProcessor<RelaySystemModel>
{
}

然后在其他地方,我会尝试像这样导入它们:

[ImportMany]
public IEnumerable<ExportFactory<IClientRequestProcessor<RelaySystemModel>, DeviceSpecific>> RelayRequestProcessors { private get; set; }

然后,在满足导入时,尝试按元数据过滤它们:

private static IEnumerable<ExportFactory<T, DeviceSpecific>> FilterForFoo<T>(IEnumerable<ExportFactory<T, DeviceSpecific>> items)
{
    return from it in items where it.Metadata.DeviceId == "<<Foo>>" select it;
}

TargetDeviceAttribute的定义如下:

[MetadataAttribute, AttributeUsage(AttributeTargets.Class)]
public class TargetDeviceAttribute : ExportAttribute, IDeviceSpecific
{
    public TargetDeviceAttribute(string deviceId)
    {
        this.DeviceId = deviceId;
    }

    public string DeviceId { get; private set; }
}

我发现正在发生的事情是部分 RelaySystemClientRequestProcessor对应两个 exports IClientRequestProcessor<RelaySystemModel>,这是导出我'我感兴趣的界面和我试图用RelaySystemClientRequestProcessor导入零件的界面。但是,“DeviceId”元数据与后者相关联而不是前者,这没有帮助。

MEF2-exports

我认为有几种方法可以解决,但我还没有完全测试过:

  1. 将属性ExportMetadata("DeviceId", "<<foo>>")应用于我的所有导出部分。

  2. 更改TargetDeviceAttribute以使用构造函数public TargetDeviceAttribute(string deviceId, Type exportType) : base(exportType)

  3. 我不赞成这些解决方案;如果我想更改元数据键,前者会出现问题,两者都会涉及改变我导出所有部件的方式。

    我想知道的是,MEF2是否提供了一种方法来导出MEF1中的元数据:通过创建自定义元数据属性并将其应用于与部件关联的所有导出。这可能吗?

1 个答案:

答案 0 :(得分:1)

原来我只需要删除6个字符。它不应该从TargetDeviceAttribute继承ExportAttribute,而应该只从Attribute继承而来:

[MetadataAttribute, AttributeUsage(AttributeTargets.Class)]
public class TargetDeviceAttribute : Attribute, IDeviceSpecific
{
    public TargetDeviceAttribute(string deviceId)
    {
        this.DeviceId = deviceId;
    }

    public string DeviceId { get; private set; }
}

在更一般的情况下,这意味着任何可以与多种可能类型相关联的元数据,但应该确保比ExportAttribute("foo", "bar")更好的静态类型安全性/可维护性,我应该如下所示:

public interface IMetadataExtension
{
    string Foo { get; }
}

public class MetadataExtension : IMetadataExtension
{
    public string Foo { get; set; }
}

[MetadataAttribute]
public class MetadataExtensionAttribute : Attribute, IMetadataExtension
{
    public MetadataExtensionAttribute(string foo)
    {
        Foo = foo;
    }

    public string Foo { get; }
}

[Export]
[MetadataExtension("bar")]
public class SomeExport
{

}