2011-07-04 27 views
14

我有一個接口:如何使用MEF繼承導出和元數據?

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

我有一個元屬性接口:

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 { ... } 

然後我嘗試導入指標(我可以看到無論是在cataloge)

以下的回報是MetricA和MetricB

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

但是下面只返回MetricB和NOT MetricA

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

有什麼想法爲什麼?

(注意MetricB重複的出口(它已經從執行IMetric))

感謝

大衛

+3

+1有趣的問題,期待看到答案。難道不可能通過以下方法來解決這個問題:不用在IMetric上使用'InheritedExport',你只能使用'MetricAttribute',因爲你必須在派生類型上聲明它。在'MetricAttribute'中,你可以調用'base(typeof(IMetric))'。您尚未提供有關「MetricAttribute」實現的更多信息,也許您已在此處執行此操作。 –

+0

@ba_friend - 謝謝我已經試過你的建議,雖然我不太清楚爲什麼很好地工作?我仍然有興趣瞭解爲什麼原始代碼不起作用 – GreyCloud

+0

我也是,我想自己嘗試一下,但目前還不行。 –

回答

14

我已經看到了這個問題,但是從我可以第一次理解,元數據是在類型級別按照導出生成的。因此,給定:

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

} 

您有兩種這種類型的出口。您的出口MetricA由您的MetricAttribute隱含提供,您的界面上有InheritedExport(typeof(IMetric))屬性提供的IMetric的繼承導出。

如果您查看容器,您會注意到爲MetricA定義了兩個導出。這是第一個,其元數據:

enter image description here

這裏是第二:

enter image description here

你會發現,元數據上的MetricA出口完成的,而不是繼承導出。如果我添加了另一個導出,例如[Export("test")]MetricA,則會得到另一個導出定義,對於名爲「test」的合同,MetricNameMetricDescription具有相同的元數據項。這表明,在分析類型時,會標識導出屬性,並且創建的導出定義包括在抽象樹中的同一級別指定的元數據。

做你想做的最簡單的方法,就是放棄了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>()的兩個出口。

+0

感謝您的詳細解答。我想我明白你的意思 - 總結:問題是元數據與出口鏈接,但是inheritedexport似乎並沒有鏈接到實現類的元數據(一個奇怪的設計決定!)。然後一個解決方案就是ba_friend說要獲得屬性來執行導出,以便導出和元數據鏈接。我會接受你的答案,但我不知道是否有可能將繼承導出與元數據一起使用 - 但也許這是我應該發佈的另一個問題!再次感謝 :) – GreyCloud

3

我遇到了同樣的問題,發現一個不同的解決方案,對我來說工作得很好: 我剛剛添加元數據到接口!

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

您可以將字段留空或默認使用null,但在此處指定元數據很重要。 然後你沒有導出屬性指定類:

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

要知道,你可以可以只指定一個元數據,但第二個將不description在這種情況下,這將是null!所以接口中的元數據不是默認值。 這所有的一切工作對我來說,我可以用我的元數據使用InheritedExport :-)

2

澄清關於馬修的回答:

當你定義自定義元數據屬性MetricAttribute類和ExportAttribute繼承,你基本上是將[Export]屬性添加到您用[Metric]屬性修飾的所有類。這意味着您不再需要接口上的[InheritedExport]屬性,因爲它僅創建不帶任何元數據的單獨導出定義。

如果你想創建一個更可重複使用的元數據屬性,你可以公開你的MetricAttributeExportAttribute構造函數的參數如下:

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 { ... } 
定義

附:

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