遲延(Lazy)加載導出部件(Export Part)與元數據(Metadata)
MEF中使用導出與導入,實質上就是對一個對象的實例化的過程,通過MEF的特性降低了對象的直接依賴,從而讓系統的設計達到一種高 靈活、高擴展性的效果。在具體的設計開發中,存在著某些對象是不需要在系統運行或者的附屬對象初始化的時候進行實例化的,僅僅只 需要在需要使用到他的時候才會進行實例化,從系統的上來說這也是提高系統性能的一種可行的實現方式,這種方式就可以理解為對象的 遲延初始化,或者叫遲延加載。MEF也對此使用場景提供了完善的實現機制,下面來看看在MEF中的遲延初始化是如何使用的。
namespace MEFTraining.LzayImports
{
public interface ILogger
{
void WriteLog(string message);
}
[Export(typeof(ILogger))]
public class DBLogger : ILogger
{
public void WriteLog(string message)
{
MessageBox.Show(message);
}
}
}
通過使用前幾篇博文中使用的日志組件為例,在日志記錄的具體實現對象上進行對象的導出[Export]配置。如果是使用傳統的方式進行 部件的導入則如下代碼塊所示:
[Import(typeof(ILogger))]
public ILogger Logger { get; set; }
如果需要進行遲延(Lazy)加載,MEF專門提供了用於遲延加載的方式,既使用Lazy類來完成遲延加載,然後通過其他屬性Value獲取到 所加載到的對象。詳細的使用如下代碼塊:
public partial class MainPage : UserControl
{
//傳統加載
[Import(typeof(ILogger))]
public ILogger Logger { get; set; }
//遲延加載
[Import]
public Lazy<ILogger> Service;
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
Logger.WriteLog("日志內容");
Service.Value.WriteLog("日志內容");
}
}
通過調試輸出可以得到使用遲延導入的對象的詳細信息,下面是通過在命令窗口中輸出的Service和Service.Value的詳細信息。
Service
ThreadSafetyMode=PublicationOnly, IsValueCreated=true, IsValueFaulted=false, Value= {MEFTraining.LzayImports.DBLogger}
IsValueCreated: true
Service.Value
{MEFTraining.LzayImports.DBLogger}
[MEFTraining.LzayImports.DBLogger]: {MEFTraining.LzayImports.DBLogger}
遲延加載還支持元數據的導出和導入,主要使用[MetadataAttribute]特性實現,實際開發中可以進行自定義元數據結構,這裡以一個 空的元數據接口進行元數據的導入應用演示。
public interface IMetadata
{
}
在導出部件中就可以使用元數據特性進行聲明,如下簡單的應用。
[MetadataAttribute]
[Export(typeof(Users))]
public class Users
{
public string UserName = "張三";
}
元數據的導入應用如下代碼塊所示:
public partial class MetadataControl : UserControl
{
[Import(typeof(Users))]
public Lazy<Users,IMetadata> Users { get; set; }
public MetadataControl()
{
InitializeComponent();
//宿主MEF托管擴展容器
CompositionInitializer.SatisfyImports(this);
MessageBox.Show(Users.Value.UserName);
}
}
對於的調試輸出為下面代碼塊所示:
Users
ThreadSafetyMode=PublicationOnly, IsValueCreated=true, IsValueFaulted=false, Value={MEFTraining.LzayImports.Users}
base {System.Lazy<MEFTraining.LzayImports.Users>}: ThreadSafetyMode=PublicationOnly, IsValueCreated=true, IsValueFaulted=false, Value={MEFTraining.LzayImports.Users}
Metadata: {_proxy_MEFTraining.LzayImports.IMetadata_0174a468-9771-4271-a37e-9a4a83eca6bd}
MEF中也提供了專門用於元數據導入、導出的特性[ExportMetadata],使用ExportMetadata基本可以滿足大部分元數據的導出、導入支 持。通過修改上面的示例來實現自定義元數據結構的導入、導出應用演示。
public interface IMetadata
{
string Name { get; }
}
[ExportMetadata("Name","李四")]
[Export(typeof(Users))]
public class Users
{
public string UserName = "張三";
}
上面的示例代碼演示了通過元數據導出屬性名為“Name”,其值為“李四”的元數據信息,並且還定義了一個用於承載元數據結構的結 構,接下來就可以通過遲延加載導入,進行元數據的獲取了。
public partial class MetadataControl : UserControl
{
[Import(typeof(Users))]
public Lazy<Users,IMetadata> Users { get; set; }
public MetadataControl()
{
InitializeComponent();
//宿主MEF托管擴展容器
CompositionInitializer.SatisfyImports(this);
MessageBox.Show(Users.Value.UserName);
}
}
下圖為允許調試中的截圖,可以很清楚的看到,在進行遲延導入的時候已經將導出部件中的元數據信息成功的導入到了當前對象實例屬 性中。
下面是完整的元數據應用實例代碼。
namespace MEFTraining.LzayImports
{
public partial class MetadataControl : UserControl
{
[Import(typeof(Users))]
public Lazy<Users,IMetadata> Users { get; set; }
public MetadataControl()
{
InitializeComponent();
//宿主MEF托管擴展容器
CompositionInitializer.SatisfyImports(this);
MessageBox.Show(Users.Value.UserName);
}
}
public interface IMetadata
{
string Name { get; }
}
[ExportMetadata("Name","李四")]
[Export(typeof(Users))]
public class Users
{
public string UserName = "張三";
}
}
除此之外,遲延加載也是支持弱類型的元數據類型的,也可以對元數據進行過濾,這裡就不做詳細的介紹,有興趣的朋友可以自己去研 究研究。