2012-08-26 21 views
3

我正在使用MEF來編寫來自幾個程序集的導出類型。我正在使用一個基類,它應該是派生類中指定的ImportMany依賴項。它看起來是這樣的:MEF的ImportMany在基類中導入所有組件的所有導出 - 如何防止這種情況?

基地大會:

public abstract class BaseClass 
{ 
    [ImportMany(typeof(IDependency)] 
    public IEnumerable<IDependency> Dependencies { get; private set; } 

    protected BaseClass() 
    { 
     var catalog = GetCatalog(); 
     var container = new CompositionContainer(catalog); 
     container.ComposeParts(this); 
    } 

    protected abstract ComposablePartCatalog GetCatalog(); 
} 

議會答:

[Export(typeof(BaseClass))] 
public class MyA : BaseClass 
{ 
    protected override ComposablePartCatalog GetCatalog() 
    { 
     return new AssemblyCatalog(Assembly.GetExecutingAssembly()); 
    } 
} 

[Export(typeof(IDependency)] 
public class DependencyA1 : IDependency {} 

[Export(typeof(IDependency)] 
public class DependencyA2 : IDependency {} 

大會B:

[Export(typeof(BaseClass))] 
public class MyB : BaseClass 
{ 
    protected override ComposablePartCatalog GetCatalog() 
    { 
     return new AssemblyCatalog(Assembly.GetExecutingAssembly()); 
    } 
} 

[Export(typeof(IDependency)] 
public class DependencyB1 : IDependency {} 

[Export(typeof(IDependency)] 
public class DependencyB2 : IDependency {} 

我然後撰寫一切都在底座組件:

static void Main(string[] args) 
{ 
    DirectoryCatalog catalog = new DirectoryCatalog(path, "*.dll"); 
    var container = new CompositionContainer(catalog); 
    IEnumerable<BaseClass> values = container.GetExportedValues<BaseClass>(); 

    // both BaseClass instances now have 4 Dependencies - from both Assemby A and Assembly B! 
} 

我遇到的,當我使用MEF撰寫既MyAMyB的問題,每個包含出口IDependency -ies從兩個組件!我只想要MyA包含出口DependencyA1DependencyA2,與MyB相同。

我知道我可能應該爲此使用依賴注入容器,但我希望可以使用MEF嗎?

+0

只是一些注意事項 - 用構造函數做構圖 - 我已經看到了很多,這不是一個好設計的想法。建議您的應用程序的一個部分處理與組合容器有關的所有事情,這就是所謂的* CompositionRoot *。理想情況下,您的組件應設計爲不受任何擴展性或IoC容器的影響,因此您可以獨立構建和測試它們。爲了做到這一點,雖然旋轉一個'CompositionContainer'的新實例相對便宜,但編目創建可能很昂貴。 –

+0

另一點需要考慮的是,您正在從構造函數調用虛擬方法,這意味着您不能再保證您的'BaseClass'構造函數將完成,因爲它現在依賴於回調函數的繼承層次結構。如果你的'override'方法試圖使用你的子類類型的實例成員 - 你最終可能拋出'NullReferenceException'實例,因爲這些實例成員可能還沒有被初始化。 –

+0

@MatthewAbbott RE構造函數中的虛擬調用,你是對的,這只是爲了這個例子。在我的「真實」應用程序中,我沒有從構造函數調用虛擬方法。 –

回答

1

在另一個組合物的鼻子下面做一個組合物是相當討厭的;)。

所以我會解決手動調用container.GetExportedValues並在構造函數中通過你自己設置屬性的方式來擺脫[ImportMany]全部。 並且它不在外部組合物上操作。

HTH 阿里爾

+0

優秀!我刪除了'ImportMany'屬性,並用'GetExportedValues '的簡單調用代替它。這解決了問題!謝了哥們! –

1

你正在做的MEF周圍一些奇怪的舞蹈用這種方法,你基本上構成BaseClass的多次將根據出現不同的結果上組成發生最後一次。當前編寫代碼的方式是在Main中發生的組合將是最後一次設置ImportMany的組合,因爲這發生在構造函數調用BaseClass之後。與Ariel類似,我會建議您不要在同一個對象上做多個作品。

如果你必須做這樣的事情與MEF這裏有一些方法,我可以看到它可能工作: 1)不要做第二個組成構造,而是使用IPartImportsSatisfiedNotification和OnImportsSatisifed做第二次composistion,儘管當你第二次創作時要留意第二次調用這個方法。 2)按照Ariel的建議,不要使用ImportMany,而是簡單地使用GetExportedValues將該字段設置爲其他裝配體級別目錄。請記住,仍然在做一個大的假設,即每個程序集只有一個派生類,否則您仍會遇到重疊。 3)您可以將ImportMany移動到派生類中,併爲每個派生類型(即IADependency或IBDendency)導入唯一的依賴類型。 4)您可以使用元數據來篩選特定派生類型的導入。

我不確定這些都是完美的,但如果我選擇一個選項,我可能會去#4的一些變化,並使用元數據過濾進口之間。請參閱How does MEF determine the order of its imports?,其中顯示瞭如何對導入進行排序,但存在用於篩選它們的類似代碼示例。

相關問題