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 = "张三";
}
}
除此之外,迟延加载也是支持弱类型的元数据类型的,也可以对元数据进行过滤,这里就不做详细的介绍,有兴趣的朋友可以自己去研究研究。