我有一个界面:
[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))
感谢
大卫
答案 0 :(得分:14)
我第一次看到这种行为,但据我所知,元数据是在类型级别的每次导出生成的。所以,给定:
[Metric("MetricA", "MetricA")]
public class MetricA : IMetric
{
}
此类型有两个导出。您导出的MetricA
由MetricAttribute
隐含地提供,并且您的接口上的IMetric
属性提供了InheritedExport(typeof(IMetric))
的继承导出。
如果查看容器,您会注意到为MetricA
定义的两个导出。这是第一个及其元数据:
这是第二个:
您会注意到元数据是在导出MetricA
时完成的,而不是继承的导出。如果我添加了进一步的导出,让我们说[Export("test")]
到MetricA
,则会得到另一个导出定义,其中MetricName
和MetricDescription
的元数据项目与“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 { ... }