3

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

特别是,我有许多使用自定义导出元数据的类,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对应于两个导出: IClientRequestProcessor<RelaySystemModel>,这是我感兴趣的导出和我尝试导入该部分的接口,和RelaySystemClientRequestProcessor。但是,“DeviceId”元数据与后者关联而不与前者关联,这没有帮助。

MEF2-出口

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

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

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

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

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

4

1 回答 1

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
{

}
于 2016-10-04T12:02:41.033 回答