【问题标题】:Why does MEF2 not apply metadata attributes to all part exports?为什么 MEF2 不对所有部件导出应用元数据属性?
【发布时间】:2016-10-04 08:45:10
【问题描述】:

我正在尝试将一组基于 .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; }
}

我发现发生的事情是 part RelaySystemClientRequestProcessor 对应于两个 exportsIClientRequestProcessor&lt;RelaySystemModel&gt;,这是我感兴趣的导出和我尝试导入部件的界面和RelaySystemClientRequestProcessor。但是,“DeviceId”元数据与后者关联,而不与前者关联,这没有帮助。

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

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

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

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

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

【问题讨论】:

    标签: c# mef mef2


    【解决方案1】:

    原来我只需要删除 6 个字符。与其让TargetDeviceAttributeExportAttribute 继承,不如从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
    {
    
    }
    

    【讨论】:

      猜你喜欢
      • 2015-05-28
      • 2013-08-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-15
      • 1970-01-01
      • 2021-11-26
      • 2016-07-12
      • 1970-01-01
      相关资源
      最近更新 更多