MEF 的導出/導入本質是物件實例化過程,透過屬性降低直接相依。實務上,某些物件不需在啟動時建立,僅在實際使用時才實例化,這就是延遲初始化,能有效提升效能。MEF 內建 Lazy<T> 支援此場景。
定義介面與實作:
public interface ILogger
{
void WriteLog(string message);
}
[Export(typeof(ILogger))]
public class DBLogger : ILogger
{
public void WriteLog(string message) => MessageBox.Show(message);
}
傳統導入會立即建立實例:
[Import(typeof(ILogger))]
public ILogger Logger { get; set; }
改用 Lazy<T> 延遲載入:
public partial class MainPage : UserControl
{
[Import(typeof(ILogger))]
public ILogger Logger { get; set; } // 傳統
[Import]
public Lazy<ILogger> Service { get; set; } // 延遲
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
Logger.WriteLog("日誌內容"); // 立即使用
Service.Value.WriteLog("日誌內容"); // 首次存取 Value 時才建立實例
}
}
除錯輸出可見 IsValueCreated 等狀態,確認實例確實在首次存取時才建立。
MEF 支援在延遲載入時攜帶中繼資料。首先定義中繼資料介面:
public interface IMetadata
{
string Name { get; }
}
導出端使用 [ExportMetadata] 標記:
[ExportMetadata("Name", "李四")]
[Export(typeof(Users))]
public class Users
{
public string UserName = "張三";
}
導入端以 Lazy<T, TMetadata> 接收:
public partial class MetadataControl : UserControl
{
[Import(typeof(Users))]
public Lazy<Users, IMetadata> Users { get; set; }
public MetadataControl()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
MessageBox.Show(Users.Value.UserName); // 取得實例
// Users.Metadata.Name 可取得 "李四"
}
}
完整範例程式碼已包含於文章中。此外,MEF 也支援弱型別中繼資料與中繼資料篩選,進一步增強彈性。