在 Managed Extensibility Framework (MEF) 中,每個可動態組合的導出部件都擁有其生命週期。若無特殊需求,開發者通常不會顯式管理生命週期,但 MEF 實際上已為每個部件提供預設的生命週期管理機制。MEF 定義了三種建立原則:Any、Shared 與 NonShared,對應 System.ComponentModel.Composition.CreationPolicy 列舉:
namespace System.ComponentModel.Composition
{
public enum CreationPolicy
{
Any = 0,
Shared = 1,
NonShared = 2,
}
}
透過 [PartCreationPolicy] 屬性即可為部件指定生命週期。以下範例展示三種原則套用於實作 IBookService 的不同類別:
public interface IBookService
{
string GetBookName();
}
[PartCreationPolicy(CreationPolicy.Any)]
[Export(typeof(IBookService))]
public class MEFBookService : IBookService
{
public string GetBookName() => "《MEF程式設計指南》";
}
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(typeof(IBookService))]
public class ASPNETBookService : IBookService
{
public string GetBookName() => "《ASP.NET專案案例》";
}
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IBookService))]
public class SLBookService : IBookService
{
public string GetBookName() => "《Silverlight高階程式設計》";
}
在導入端,可使用 [ImportMany] 搭配 RequiredCreationPolicy 參數,只匯入符合特定生命週期的部件:
public partial class MainPage : UserControl
{
[ImportMany(RequiredCreationPolicy = CreationPolicy.Shared)]
public List<IBookService> Services { get; set; }
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
// 僅會獲得 Shared 與 Any 兩個部件(Any 可視為可共享)
int count = Services.Count; // 結果為 2
}
}
這與自訂中繼資料篩選類似,但生命週期篩選是由 MEF 內建機制直接支援,無需額外撰寫篩選邏輯。實務上應根據場景選擇:單例服務用 Shared、狀態獨立的元件用 NonShared、不確定時用 Any 讓容器決定。
除了部件生命週期,容器本身的資源管理同樣重要。MEF 建議可導入部件實作 IDisposable,當部件從容器移除時,對應資源會自動清理。需注意:組合容器釋放後,延遲載入操作將無法繼續,會拋出 ObjectDisposedException。
MEF 容器具有階層結構,最上層為應用程式層級容器,可透過 AssemblyCatalog 與 CompositionContainer 建立:
var catalog = new AssemblyCatalog(typeof(MainPage).Assembly);
var container = new CompositionContainer(catalog);
子容器通常掌管可動態組合的部件子集。例如使用 FilteredCatalog 從父容器目錄中依中繼資料篩選,再建立子容器:
var catalog = new AssemblyCatalog(typeof(MainPage).Assembly);
var parent = new CompositionContainer(catalog);
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>();
此架構讓大型應用能將部件依功能域隔離在不同子容器,既保持鬆耦合,又能精確控制生命週期與可見範圍。