MEF中的每一個可進行動態裝配的導出部件都是具有生命週期的,在沒有特別需求的情況下一般都沒有對生命週期進行管理,而實際上MEF已爲每一個部件進行了默認的生命週期管理,MEF的生命週期分爲三種:Any、Shared及NonShared,被定義在System.ComponentModel.Composition.CreationPolicy枚舉對象中。
{
public enum CreationPolicy
{
Any = 0,
Shared = 1,
NonShared = 2,
}
}
Any表示可共享或不共享,部件的實例用MEF容器根據不同的請求需求自動控制;Shared表示共享部件,既Shared類型的插件部件可以在多個MEF組合容器中共用;其次是NonShared類型,表示不共享部件實例,每當有新的請求就會創建一個新的對象實例。在MEF中,通過PartCreationPolicyAttribute特性實現對部件的生命週期配置。
{
string GetBookName();
}
[PartCreationPolicy(CreationPolicy.Any)]
[Export(typeof(IBookService))]
public class MEFBookService : IBookService
{
public string GetBookName()
{
return "《MEF程序設計指南》";
}
}
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(typeof(IBookService))]
public class ASPNETBookService : IBookService
{
public string GetBookName()
{
return "《ASP.NET項目案例》";
}
}
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IBookService))]
public class SLBookService : IBookService
{
public string GetBookName()
{
return "《Silverlight高級編程》";
}
}
如上示例代碼分別演示了使用Any、Shared及NonShared類型的生命週期託管類型對不同的對象進行導出部件配置。接下來通過導入部件並加入生命週期託管篩選,詳細應用如下代碼塊所示:
{
[ImportMany(RequiredCreationPolicy = CreationPolicy.Shared)]
public List<IBookService> Service { get; set; }
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
//得到成功裝配的部件總數爲2,因爲Any類型是可以共存於多個MEF容器的。
int count = Service.Count;
}
}
表面上看去和上一篇指南中介紹的部件的篩選過濾功能非常相似,不同是的過濾篩選是通過自定義篩選策略實現,而這裏是通過MEF生命週期範圍託管來實現的。在實際的項目開發中需根據不同的應用場景確定具體的技術實現方案。
除了容器部件的生命週期託管,我們也得考慮部件容器自身的生命週期,容器什麼時候釋放資源,時候時候釋放其內部部件的資源佔用等。爲了提高系統的整體性能,MEF建議將每一個可導入部件實現IDisposable 接口,用於資源的佔用處理,如果部件從MEF容器中移除那麼所對應占用的資源也會自動的清理。這裏需要注意一點,就是當組合容器被釋放掉後遲延加載的操作就不能再繼續工作了,會拋出System.ObjectDisposedException異常。
如上圖所示,MEF的容器是具有層次結構的,最高層級容器爲程序直接應用級容器,可以通過以下的代碼獲取到。
var container = new CompositionContainer(catalog);
位於頂級容器之下的子容器,通常來說都是控制着一些可動態裝配的部件對象,如同上一篇指南中介紹到使用過濾器篩選部件的應用案例,通過過濾表達式從頂級容器中進行篩選,得出了新的MEF容器child,child託管着根據條件過濾篩選出來的所有結果部件對象。詳細代碼如下:
var catalog = new AssemblyCatalog(typeof(MainPage).Assembly);
//將目錄裝載進MEF組合容器
var parent = new CompositionContainer(catalog);
//通過元數據過濾篩選出元數據名稱爲"UC"值爲"CC"的組合部件
var filteredCat = new FilteredCatalog(catalog,
def => def.Metadata.ContainsKey("UC") &&
def.Metadata["UC"].ToString() == "CC");
var child = new CompositionContainer(filteredCat, parent);
var control = child.GetExportedValue<UserControl>();
MEF官方網站:http://mef.codeplex.com/
MEF程序設計指南二:Silverlight中使用CompositionInitializer宿主MEF
MEF程序設計指南三:MEF中組合部件(Composable Parts)與契約(Contracts)的基本應用
MEF程序設計指南四:使用MEF聲明導出(Exports)與導入(Imports)
MEF程序設計指南五:遲延(Lazy)加載導出部件(Export Part)與元數據(Metadata)