通过AttributeedModelPrograming,我们可以声明暴露组件,依赖组件,发现组件,但是所有这些需要有一个触发点。即需要把所有这些组合在一起来协同工作,最终实现依赖注入。这就是Container层所做的事情.

CompositionContainer            

CompositionContainer在MEF中负责组合其他元素来实现依赖注入。看看他的一个构造函数:

public CompositionContainer(
ComposablePartCatalog catalog,//指明如何发现组件
bool isThreadSafe,//指明是否需要线程安全,这个如果在多线程模型下需要设为true
params ExportProvider[] providers
)

可以看出,我们把Catalog传入container,即告诉了container如何去发现组件,再结合通过Export/Import各种attributes定义好的依赖模型。不难理解container已经可以去根据依赖模型注入依赖了。接下来就是触发点。Container提供了一系列API来填充给定组件中的依赖。主要是如下几个:

Compose(CompositionBatch)

Adds or removes the parts in the specified CompositionBatch from the container and executes composition.

     
GetExportedValue<T>()

Returns the exported object with the contract name derived from the specified type parameter. If there is not exactly one matching exported object, an exception is thrown.(Inherited fromExportProvider.)

GetExportedValue<T>(String)

Returns the exported object with the specified contract name. If there is not exactly one matching exported object, an exception is thrown.(Inherited from ExportProvider.)

     
SatisfyImportsOnce(ComposablePart)

Satisfies the imports of the specified ComposablePart object without registering it for recomposition.(当前组件不会被注册为Export组件)

     

然后在AttributedModelService中提供了一系列面向组件实例的API,常用的Extension方法有如下几个:

     
ComposeParts(CompositionContainer, Object[])

Creates composable parts from an array of attributed objects and composes them in the specified composition container.

     
CreatePart(Object)

Creates a composable part from the specified attributed object.

     
SatisfyImportsOnce(ICompositionService, Object)

Composes the specified part by using the specified composition service, with recomposition disabled.

     

ExportProvider          

其实到这里似乎可以认为,Container负责了实际组件对象的创建。因为Catalog只定义了组件的发现,然后生成PartDefinition。但其实真实情况不是这样,Container其实这是个接口层,真正负责组件实例的创建是由第一篇中的那幅图中还没有用过的ExportProvider来负责。看看ExportProvider的接口定义:

看上去有很多方法,其实都是在做一件事,根据ImportDefinition来得到一个Export对象(组件实例的包装)

内置的ExportProvider有如下几种:

CompositionContainer - CompositionContainer自身其实也是一种ExportProvider

MutableExportProvider - 当创建CompositionContainer时,Container内部会创建该ExportProvider,然后负责管理通过调用Container接口手动添加的组件

ComposablePartCatalogExportProvider - 它负责管理通过PartCatalog发现的组件,当创建CompositionContainer的时候如果传入了Catalog,Container会创建该ExportProvider.

AggregatingExportProvider - 根据名字即可知道,该ExportProvider是用来组合其他ExportProvider的,上述创建CompositionContainer的时候创建的ExportProvider最后都会聚合在该Provier中统一管理。

也可以自定义ExportProvider,然后创建CompositionContainer的时候加入到Container中,则可以对MEF进行扩展。

Recomposition            

在依赖的组件已经注入之后,如果后续对Export的组件进行添加和删除后,想要更新原来已经注入的依赖组件。则可以使用Recomposition。看如下代码:

public interface ILog
{ } [Export(typeof(ILog))]
[ExportMetadata("Type", "file")]
public class FileLog : ILog
{ } [Export(typeof(ILog))]
[ExportMetadata("Type", "db")]
public class DBLog : ILog
{ } public class TaskExecutor
{
[ImportMany(typeof(ILog), AllowRecomposition = true)]
public IEnumerable<ILog> _loggers;
} class Program
{ static void Main(string[] args)
{ var container = new CompositionContainer(new TypeCatalog(typeof(DBLog))); var taskExecutor = new TaskExecutor();
container.ComposeParts(taskExecutor); Console.WriteLine(taskExecutor._loggers.Count());//此时只有DBLog满足注入条件因此logger的个数为1 var fileLog = new FileLog();
var fileLogPart = AttributedModelServices.CreatePart(fileLog);
var partBatch = new CompositionBatch();
partBatch.AddPart(fileLogPart);//添加FileLog满足ILog的注入条件 container.Compose(partBatch); Console.WriteLine(taskExecutor._loggers.Count());//Recomposition会更新logger的注入依赖,此时的logger个数为2 Console.ReadKey();
}
}

MEF学习总结(4)---Container层的更多相关文章

  1. MEF学习总结(2)---Primitive层

    Primitive层是属于依赖注入的通用模型,主要有如下核心类型: 1. ComposablePart是核心类,他表示组件容器中的每一个组件,是对真正组件实例的包装.ExportDefinition属 ...

  2. C#可扩展编程之MEF学习笔记(五):MEF高级进阶

    好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...

  3. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  4. C#可扩展编程之MEF学习笔记(三):导出类的方法和属性

    前面说完了导入和导出的几种方法,如果大家细心的话会注意到前面我们导出的都是类,那么方法和属性能不能导出呢???答案是肯定的,下面就来说下MEF是如何导出方法和属性的. 还是前面的代码,第二篇中已经提供 ...

  5. C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)

    上一篇学习完了MEF的基础知识,编写了一个简单的DEMO,接下来接着上篇的内容继续学习,如果没有看过上一篇的内容, 请阅读:http://www.cnblogs.com/yunfeifei/p/392 ...

  6. C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo

    在文章开始之前,首先简单介绍一下什么是MEF,MEF,全称Managed Extensibility Framework(托管可扩展框架).单从名字我们不难发现:MEF是专门致力于解决扩展性问题的框架 ...

  7. MEF学习总结(3)---Attribute Model Programing

    上一片介绍了Primitive层,Attribute Model可以认为是对Primitive的上层实现.主要包括如下内容: 1. 一系列的Attribute来定义Import和Export 常用的有 ...

  8. MEF学习总结(1)---总体架构

    用了很久的MEF框架来做依赖注入,最近想把它的原理和机构总结一下,主要包括如下几个方面: 1. 总体架构 2. .Net Composition Primitive 3. Attribute Mode ...

  9. C#可扩展编程之MEF学习

    MEF系列文章: C#可扩展编程之MEF学习笔记(一):MEF简介及简单的Demo C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import) C#可扩展编程之MEF学习 ...

随机推荐

  1. 大白话,讲编程之《ES6系列连载》汇总

    如果你经历过2,3年前的前端开发,你一定感受过兼容IE6,7的痛苦,一定用过网页三剑客的dreamweaver编写html,面试的时候面试官一定会问你:会用PS切图吗? 刚开始的时候你发现,web前端 ...

  2. gitlab下载安装及部署

    初次操作成功,记录一下   1. 安装依赖软件 yum -y install policycoreutils openssh-server openssh-clients postfix   2.设置 ...

  3. 八、dbms_rls(实现精细访问控制)

    1.概述 本报只适用于Oracle Enterprise Edition,它用于实现精细访问控制,并且精细访问控制是通过在SQL语句中动态增加谓词(WHERE子句)来实现的.通过使用ORACLE的精细 ...

  4. PHP Socket(套接字连接)扩展简介和使用方法

    PHP socket扩展是基于流行的BSD sockets,实现了和socket通讯功能的底层接口,它可以和客户端一样当做一个socket服务器. 使用这些函数时请注意,虽然他们中有很多和C函数同名的 ...

  5. shell脚本实例三

    练习一:获得连通主机的ip和hostname1.脚本编写 vim  checkhost.sh #!/bin/bashAuto_conn(){/usr/bin/expect << EOFse ...

  6. 在头文件中声明class 类 与 include类所在的头文件区别---理解

    在头文件中声明class 类 与 include类所在的头文件的理解: 在头文件中,声明类 它告诉编译器:存在这样的类.而实际的类则可以位于同一个编译单元中,也可以放在其他编译单元中.没有这个类原型, ...

  7. 2PC

    两阶段提交()Two-Phase Commit):是计算机网络尤其是在数据库领域内,为了使基于分布式系统架构下的所有节点在进行事务处理过程中能够保持原子性和一致性而设计的一种算法.通常,二阶段提交协议 ...

  8. mysql动态扩容调研

    MySQL动态扩容方案 目前可用方案 MySQL的复制: 一个Master数据库,多个Salve,然后利用MySQL的异步复制能力实现读写分离,这个方案目前应用比较广泛,这种技术对于以读为主的应用很有 ...

  9. 开源一款资源分享与下载工具 —— 电驴(eMule)

    这里分享一款资源分享与下载工具--电驴,其实严格来说,应该叫电骡,这是我维护的版本,eMuleVeryCD版本,VeryCD是一个不错的资源分享网站:http://www.verycd.com/.大概 ...

  10. Swift UITextField各种属性的设置

    //MARK: 文本输入框 func _initTextField() { //如果需要在模拟器中调用电脑的键盘 快捷键:command + shift + k let textField = UIT ...