代码改变世界

我学MEF系列(5):创建策略(Creation Policy )和生命周期(Life Cycle)

2011-12-14 23:32  ps_zw  阅读(3576)  评论(1编辑  收藏  举报

前言

在前面的介绍中我们已经知道:导入和导出的匹配成功需要ContractType,ContractName,Metadata都匹配,这里我们还要介绍一个新的东西:创建策略(creation policy )。有时候我们在容器中的实例在每一个导入之间共享,即单例;有时候我们需要让每一个导入都拥有一个各自的实例,这在MEF中就是有创建策略决定的。

生命周期(Life Cycle),每一个MEF的部件在容器中都有自己的生命周期,何时创建,何时释放等。本文就主要介绍一下MEF中得创建策略和生命周期

创建策略

      创建策略,其实就是组合容器决定如何创建部件。在组合容器组合部件时,如果导入和导出匹配成功,则组合容器会将导入成员的值设置成为导出的实例。因此,导出部件的创建策略决定了部件来源于何处:是现有实例还是新实例。

     MEF的创建策略有:Shared(共享)和NonShared(非共享)。

     使用Shared创建策略的部件将在每一个导入部件中共享实例。仅当容器中没有该部件的实例时才会创建新实例。使用共享策略创建的部件可以是提供服务的部件,以及较占用内存的部件。他们的内部状态应该尽可能少得受外界影响。

     使用NonShared策略的部件在匹配每一个导入时都会有新的实例。这些部件的内部状态都是相互独立的,当某些部件需要保持特定的状态时可以使用这种策略。

    MEF关于创建策略提供的特性有3种:Shared,NonShared,Any(请注意Any和Shared的区别,创建策略只有两种)。导入和导出的默认值都是Any。当导入导出都是用默认创建策略,或者都是用默认,MEF将默认创建策略为Shared。创建策略的匹配与否也决定了导出部件和导入能否成功匹配。以下情况可视为匹配成功:

1. 标记为Any的导出部件与Shared和NonShared的导入均能成功匹配;

2. 创建策略为Shared或NonShared的导出以及标记为Any的导入匹配成功;

3. 创建策略为Shared的导出只能与创建策略为Shared和标记为Any匹配成功;

4. 创建策略为NonShared的导出只能为Shared和标记为Any的导入匹配成功。

    创建策略特性的用法:

//导入部件

[Import(RequiredCreationPolicy = CreationPolicy.Shared)]
//导出部件
[PartCreationPolicy(CreationPolicy.NonShared)]

请看一个简单的例子:

View Code
 1 //定义导出部件,创建策略为非共享
2 [Export]
3 [PartCreationPolicy(CreationPolicy.NonShared)]
4 public class FileLog
5 {
6 public void WriteLog()
7 {
8 Console.Writeline("This is FileLog!");
9 }
10 }
11
12 //定义导出部件,创建策略为非共享
13 [Export]
14 [PartCreationPolicy(CreationPolicy.Shared)]
15 public class DBLog
16 {
17 public void WriteLog()
18 {
19 Console.Writeline("This is DBLog!");
20 }
21 }
22
23
24 public class MyClass
25 {
26 //成功匹配
27 [Import(RequiredCreationPolicy = CreationPolicy.NonShared)]
28 public FileLog MyFileLog1;
29
30 //匹配失败
31 [Import(RequiredCreationPolicy = CreationPolicy.Shared)]
32 public FileLog MyFileLog2;
33
34 //匹配成功
35 [Import]
36 public DBLog MyDBLog;
37
38 }

注:到目前为止我们可以知道影响导出部件同导入部件成功匹配的主要因素大概有:ContractType(协定类型),ContractName(协定名称),Metadata(元数据),CetationPolicy(创建策略)。

生命周期

      在MEF中,生命周期是比较复杂的,在MSDN中也只用一句话带过:

     由于部件承载于组合容器中,因此其生命周期可能比普通对象更复杂。 部件可实现两个重要的生命周期相关接口:IDisposable 和 IPartImportsSatisfiedNotification。

     容器本身实现了IDisposable,在容器Dispose方法被调用时,容器会对容器中得每一个部件调用Dispose方法。一般情况下,部件只有在容器释放时才会释放资源。联想到上面介绍的创建策略,有人不禁要问如果创建策略为非共享的部件过多,很占用很多资源,不过不用担心:容器提供了 ReleaseExport 方法。此方法可以释放导出部件,并对部件占用的资源进行释放。

      如果部件实现了接口IPartImportsSatisfiedNotification ,当组合已完成并且部件的导入可供使用时,组合窗口将对部件调用接口中得方法OnImportsSatisfied。

     IPartImportsSatisfiedNotification 包含一个名为 OnImportsSatisfied 的方法。 当组合已完成并且部件的导入可供使用时,组合窗口将对实现接口的任何部件调用此方法。 部件是组合引擎创建,用于满足其他部件的导入。 在设置好部件的导入之前,您无法执行任何依赖于部件构造函数中的导入值或对这些值进行操作的初始化,除非已通过使用 ImportingConstructor 特性将这些指定为必备。 此方法通常为首选方法,但在某些情况下,构造函数注入可能不可用。 在这些情况下,可以在 OnImportsSatisfied 中执行初始化,并且部件应实现 IPartImportsSatisfiedNotification。

   灵活运用部件的生命周期在具体使用MEF中会有很大得帮助,如:我们可能将WCF,EF做成组件,然后使用MEF整合这些组件,那么在组合成功后,我们可能需要读取WCF配置发布服务,或者读取DB.config建立数据库连接等。这时在OnImportsSatisfied 中完成这些操作可能效果更好。