如何使用MEF继承导出和MetaData?

Gre*_*oud 15 .net c# mef c#-4.0

我有一个界面:

[InheritedExport(typeof(IMetric))]
public interface IMetric { ... }
Run Code Online (Sandbox Code Playgroud)

我有一个Meta属性界面:

 public interface IMetricAttribute { ... }
Run Code Online (Sandbox Code Playgroud)

以及实现它的属性:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class MetricAttribute : ExportAttribute, IMetricAttribute {
    public string MetricName { get; set; }
    public string MetricDescription { get; set; }

    public MetricAttribute(string name, string description)
        : base(typeof(MetricAttribute)) {
        this.MetricName = name;
        this.MetricDescription = description;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有两个班:

[Metric("MetricA","MetricA")]
public class MetricA: IMetric { ... }

[Export(typeof(IMetric))] <<<< THIS IS IMPORTANT
[Metric("MetricB", "MetricB")]
public class MetricB: IMetric { ... }
Run Code Online (Sandbox Code Playgroud)

然后我尝试导入指标(我可以在目录中看到)

以下返回MetricA AND MetricB

var metrics = compositionContainer.GetExports<IMetric>();
Run Code Online (Sandbox Code Playgroud)

但是,以下仅返回MetricB和NOT MetricA

var metrics = compositionContainer.GetExports<IMetric, IMetricAttribute>();
Run Code Online (Sandbox Code Playgroud)

任何想法为什么?

(注意MetricB上的重复导出(它已经实现了IMetric))

谢谢

大卫

Mat*_*ott 14

我第一次看到这种行为,但根据我的理解,元数据是在类型级别的每次导出生成的.所以,给定:

[Metric("MetricA", "MetricA")]
public class MetricA : IMetric
{

}
Run Code Online (Sandbox Code Playgroud)

您有两种此类型的导出.您的导出MetricA是由您自己提供的MetricAttribute,并且您具有IMetricInheritedExport(typeof(IMetric))接口上的属性提供的继承导出.

如果查看容器,您会注意到为其定义了两个导出MetricA.这是第一个带有元数据的:

在此输入图像描述

这是第二个:

在此输入图像描述

您会注意到元数据是在导出时完成的MetricA,而不是继承的导出.如果我加了进一步的出口,可以说[Export("test")]MetricA,你的另一个出口的定义,与相同的元数据的项目MetricNameMetricDescription一个名为"测试"的合同.这表明,在分析类型时,将标识export属性,并且创建的导出定义包括在抽象树中的同一级别指定的元数据.

做你想做的最简单的方法是退出InheritedExport,并修改你的定义MetricAttribute:

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false), MetadataAttribute]
public class MetricAttribute : ExportAttribute, IMetricAttribute
{
    public MetricAttribute(string name, string description)
        : base(typeof(IMetric))
    {
        this.MetricName = name;
        this.MetricDescription = description;
    }

    public string MetricName { get; private set; }
    public string MetricDescription { get; private set; }

}
Run Code Online (Sandbox Code Playgroud)

然后你传入typeof(IMetric)基础ExportAttribute构造函数.然后你正确地得到两个出口GetExports<IMetric>()GetExports<IMetric, IMetricAttribute>().