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

Why does MEF2 not apply metadata attributes to all part exports?

我正在尝试将一组基于 .NET Framework 的应用程序移植到 .NET Core,作为此过程的一部分,我需要从使用 MEF1 切换到 MEF2。我一直难以解决与 MEF2 相关的问题(尽管我发现 this post 真的很有帮助),但我最近偶然发现了其中一个问题背后的原因.

特别是,我有许多 classes 使用自定义 ExportAttribute 导出元数据,我想将它们全部导入另一个 class 并根据这个元数据。这在 MEF1 中一切正常,但在 MEF2 中我 运行 遇到诸如 "Export metadata for x is missing and no default value was supplied.".

之类的问题

更具体地说,我将导出的 class 注释如下:

[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 对应于两个 exportsIClientRequestProcessor<RelaySystemModel>],这是我感兴趣的导出和我尝试导入零件的界面,以及 RelaySystemClientRequestProcessor。但是,"DeviceId" 元数据 与后者而非前者相关联,这没有帮助。

虽然我还没有完全测试过,但我相信有几种方法可以解决这个问题:

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

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

我不赞成这些解决方案;如果我想更改元数据密钥,前者会有问题,并且两者都涉及更改我导出所有部分的方式。

我想知道 MEF2 是否提供了一种导出元数据的方法,就像在 MEF1 中一样:通过创建自定义元数据属性并将该元数据应用到 all 与关联的导出一部分。这可能吗?

原来我只需要删除 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; }
}

在更一般的情况下,这意味着任何元数据都可以与多种可能的类型相关联,但应该确保更好的静态类型 safety/maintainability 而不是 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
{

}