MEF框架学习之旅(七)部件的创建规则(策略)
当部件指定执行导入和组合时,组合容器将尝试查找匹配的导出。 如果它将导入与导出成功匹配,则导入成员将设置为导出的对象的实例。 导出部件的创建策略控制此实例来源于何处。
两个可能的创建策略为:“共享”和“非共享”。 在具有该协定的部件的容器中,创建策略为“共享”的部件将在每个导入之间共享。 当组合引擎找到匹配项并且必须设置导入属性时,它只有在部件尚不存在时才会实例化部件的新副本;否则它将提供现有副本。 这意味着许多对象可能会引用相同部件。 此类部件不应依赖于可能会从许多地方更改的内部状态。 此策略适用于静态部件、提供服务的部件,以及消耗大量内存或其他资源的部件。
在每次找到部件的其中一个导出的匹配导入时,将会创建创建策略为“非共享”的部件。 因此,将为与部件的其中一个已导出协定匹配的容器中的每个导入实例化一个新副本。 这些副本的内部状态将不会共享。 此策略适用于每个导入需要其自己的内部状态的部件。
MEF 中的部件创建策略可以是以下三个值之一:CreationPolicy.Shared、CreationPolicy.NonShared 或 CreationPolicy.Any。若要指定部件的创建策略,请使用 partCreationPolicy 特性修饰部件。通过对导入设置 RequiredCreationPolicy 属性,也可在导入程序端指定 PartCreationPolicy。
导入和导出都可从值 Shared、NonShared 或 Any 中指定部件的创建策略。 导入和导出的默认值均为 Any。 指定 Shared 或 NonShared 的导出将仅与指定相同值或指定 Any 的导入匹配。 同样,指定 Shared 或 NonShared 的导入将仅与指定相同值或指定 Any 的导出匹配。 就像其协定名称或协定类型不匹配的导入和导出一样,创建策略不兼容的导入和导出也不会被视为匹配。 如果导入和导出均指定 Any,或者未指定创建策略并默认为 Any,则创建策略将默认为“共享”。
【CreationPolicy】枚举的值:【Shared】代表共享部件,即单例,所有的导入都使用一个实例,如果组合引擎中没有该实例,则会创建,一旦有了,就不会再创建;【NonShared】和【Shared】相对应,即每次导入都创建一个新的实例,所有导入的实例都拥有自己唯一的状态,数据不共享;【Any】只是为了匹配导入导出,有下面一张匹配表
导出(Export):CreationPolicy |
导入(Import):CreationPolicy |
Any |
Any、NonShared、Shared |
NoneShared |
NoneShared、Any |
Shared |
Shared、Any |
只有满足上面这张表,导入导出才会匹配,下面我们做一个很简单的示例:
代码段
class Program { private static CompositionContainer container; static void Main(string[] args) { var catalog = new AssemblyCatalog(typeof(Program).Assembly); container = new CompositionContainer(catalog); var studentManager1 = container.GetExportedValue<StudentManager>(); var studentManager2 = container.GetExportedValue<StudentManager>(); Console.WriteLine(object.ReferenceEquals(studentManager1, studentManager2)); Console.WriteLine(object.ReferenceEquals(studentManager1.Student, studentManager2.Student)); Console.ReadLine(); } } //单例导出 [Export, PartCreationPolicy(CreationPolicy.Shared)] public class Student { public string Name { get; set; } public int Age { get; set; } } //非单例导出 [Export, PartCreationPolicy(CreationPolicy.NonShared)] public class StudentManager { //默认Any [Import] public Student Student { get; set; } }
最后输出的是一个false和true。学生管理类StudentManager类为NonShared,所以它每次导出都会实例化。而Student类为Shared,所以它为单例模式,仅导出一个实例。
注:
[Export, PartCreationPolicy(CreationPolicy.NonShared)]
相当于
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
此外,我们可以预先在容器中定义导出,这样的定义不需要【Export】特性描述类型,并且这样输出的永远是单例:
代码段
container.ComposeExportedValue<DateTime>(DateTime.Now);
Console.WriteLine(container.GetExportedValue<DateTime>());
相关阅读: