如何使用MEF Inherited Export&元数据?

时间:2011-07-04 11:37:16

标签: c# .net c#-4.0 mef

我有一个界面:

[InheritedExport(typeof(IMetric))]
public interface IMetric { ... }

我有一个Meta属性界面:

 public interface IMetricAttribute { ... }

以及实现它的属性:

[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;
    }
}

然后我有两个班级:

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

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

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

以下返回MetricA AND MetricB

var metrics = compositionContainer.GetExports<IMetric>();

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

var metrics = compositionContainer.GetExports<IMetric, IMetricAttribute>();

任何想法为什么?

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

感谢

大卫

3 个答案:

答案 0 :(得分:14)

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

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

}

此类型有两个导出。您导出的MetricAMetricAttribute隐含地提供,并且您的接口上的IMetric属性提供了InheritedExport(typeof(IMetric))的继承导出。

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

enter image description here

这是第二个:

enter image description here

您会注意到元数据是在导出MetricA时完成的,而不是继承的导出。如果我添加了进一步的导出,让我们说[Export("test")]MetricA,则会得到另一个导出定义,其中MetricNameMetricDescription的元数据项目与“test”的合同相同”。这表明,在分析类型时,将标识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; }

}

然后,您将typeof(IMetric)传递给基础ExportAttribute构造函数。然后,您可以正确获取GetExports<IMetric>()GetExports<IMetric, IMetricAttribute>()的两个导出。

答案 1 :(得分:3)

我遇到了同样的问题,发现了一个不同的解决方案,对我来说很好: 我刚刚在界面中添加了元数据!

[InheritedExport(typeof(IMetric))]
[Metric("name","description")]
public interface IMetric { ... }

您可以将这些字段留空或默认使用null,但在此处指定元数据非常重要。 然后指定没有导出属性的类:

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

请注意,您只能指定一个元数据,但在这种情况下,第二个元数据不会是description,它将是null!因此,界面中的元数据不是默认值。 总而言之,这对我有用,我可以将InheritedExport与我的元数据一起使用: - )

答案 2 :(得分:2)

澄清马修答案:

当您定义自定义元数据属性类<script type="text/javascript"> $(document).ready(function(){ $('#target').change(function() { $.ajax({ url: 'shelfid.php', type: 'POST', dataType: 'json', data:{ itemID: $(this).val() }, success:function(data) { $(".result").text(data); } }); }); }); </script> 并继承自MetricAttribute时,您实际上是将ExportAttribute属性添加到使用[Export]属性装饰的所有类中。这意味着您不再需要界面上的[Metric]属性,因为它只是创建了没有任何元数据的单独导出定义。

如果要创建更可重用的元数据属性,可以在[InheritedExport]中公开ExportAttribute构造函数参数,如下所示:

MetricAttribute

通过引入public MetricAttribute(Type contractType, string name, string description) : base(contractType) { this.MetricName = name; this.MetricDescription = description; } 变量,您现在可以补充

的定义
contractType

使用:

[Export(typeof(IMetric))]
[Metric("MetricB", "MetricB")]
public class MetricB: IMetric { ... }
相关问题