MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要的库,Visual Studio 2010 Code Editor的扩展支持也是基于MEF构建的。MEF的目标是简化创建可扩展的应用程序,其核心类是ComposablePart,即具有组合能力的组 件,每一个称为ComposablePart(中文可为可组合构件,不过下文一直采用英文来表示,这样比较贴切)的组件可以组合(称为Import)其它 组件的功能(其它组件通过声明Export提供功能)并且它也可以通过定义Export将其功能暴露给其它组件。ComposablePart通过组件目 录(ComposablePartCatalog)来搜索发现需要的功能,组件目录可以是一个物理文件目录、网络存储等。每一个 ComposablePart还具备动态组合的能力,在必要的情况下可以重新组合功能。本文将采用自底向上的思路体验一下MEF的设计思想。

1 无废话MEF

MEF 的核心是可组合组件ComposablePart,它由ComposablePartDefintion来描述和创建。每一个可组合组件通过定义 ExportDefintion向其它组件提供功能,通过ImportDefinition引用其它组件的功能,通过Metadata来描述组件自身的信 息。在创建一个ComposablePart组件后,通过在组件目录(ComposableCatalog)搜索需要的功能实现组件组合。

2 典型的MEF组合过程

(1)创建组件目录(如AssemblyCatalog)

(2)创建组合容器CompositionContainer,组件容器通过组件目录搜索组件的定义

(3)创建一个组件

(4)从组件容器获取其它组件功能的定义,然后执行匹配组合

示例代码如下:

1 var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); //创建一个程序集目录,用于从一个程序集获取所有的组件定义
2 var container = new CompositionContainer(catalog); //创建一个组合容器
3 var composablePart = new MyComponent();
4 container.ComposeParts(composablePart); //执行组合,从容器中获取ExportDefinition并创建实例组合在一起
5 // composablePart组合完成以供使用

其原理如下图(来自mef.codeplex.com官方网站):

3 MEF本质——组合基元

组合基元是对提供具有可扩展、可组合能力的组件的“本质”支持,它处于MEF的最底层,是整个Framework的核心类,由6个类构成,如下图所示(该图来自MEF白皮书,白皮书有点抽象,不过看起来很过瘾,后面附上本人翻译的中文版)。

组合基元类的描述如下:

(1)ComposablePart:
即可组合组件,是组合基元的核心类。ExportDefinitions表示该组件提供的功能的描述;而ImportDefinitions则是对引用其
它组件功能的约束的描述。Metadata是对组件自身的特殊标识,当一个ComposablePart通过Import引用其它组件功能时,元数据可能
作为满足引用功能的约束的一个条件。

(2)ExportDefinition:定义ComposablePart向其它组件提供的功能,这个功能使用一个ContactName和Metadata来描述。ContactName即使用这个功能的契约,Metadata用于进一步描述这个功能。

(3)ImportDefinition:
定义ComposablePart对其它组件提供的功能的引用,即引用了另一个组件的Exports。ImportDefintion使用一个表达式来描
述约束,它在Constraint这个属性定义,其类型为Expression<Func<ExportDefinition,
bool>>。这个表达式用于对一个ExportDefintion做匹配判定,其匹配方法如下:

var allExportDefs = …// 从ComposablePartCatalog获取所有ExportDefinition

var constraintDelegate= Constraint.Compile(); //编译成匹配函数的代理

var satisfiedExportDefs = allExportDefs .FindAll(constraintDelegate); //使用匹配函数的代理来过滤所有的ExportDefs

(4)ComposableDefinition:
即ComposablePart定义,是ComposablePart的工厂,该类定义了一类ComposablePart引用的功能、暴露的功能及其自
身的元数据。引用的功能在ImportDefinitions中描述,暴露的功能通过ExportDefinitions描述。而Metadata则是对
组件自身的描述,在MEF中一般用于在一个组件引用(Import)另一个组件功能时,通过对另一个组件的元数据进行匹配,从而来确定是否要组合另一个组
件提供的功能。该类是ComposablePart的工厂,提供了CreatePart方法。

(5)ComposablePartCatalog:可组合组件目录,用于发现组件,这些组件可能来自物理目录、网络存储等。

4 如何使用MEF


上面,我们描述了MEF的核心——组合基元,组合基元听起来很简单,很容易理解,但是想直接使用组合基元来编写一个
ComposablePartDefinition却不是那么容易了,在MEF的实现,这些类都是一些抽象类,用于描述整个可扩展框架的模型。我先不想说
明白MEF到底是如何来使用组合基元,先看示例好了。

4.1 定义ComposablePartDefinition

MEF通过引入一个基于特性的编程模型来简化ComposablePart的定义,如下所示的MessageSender和Processor类均是ComposablePart定义。


 1 public class MessageSender 
 2 { 
 3   [Export("MessageSender")] 
 4   public void Send(string message) 
 5   { 
 6     Console.WriteLine(message); 
 7   } 
 8 }
 9 [Export] 
10 public class Processor 
11 { 
12   [Import("MessageSender")] 
13   public Action<string> MessageSender { get; set; }
14   public void Send() 
15   { 
16     MessageSender("Processed"); 
17   } 
18 } 

4.2 创建ComposablePart


1 var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); //创建一个程序集目录,用于从一个程序集获取所有的组件定义
2 var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); //创建组件目录 
3 var container = new CompositionContainer(assemblyCatalog); //创建组合容器
4 var processorPart = new Processor(); 
5 container.ComposeParts(processorPart); //执行组合
6 processorPart.Send();
7 Console.ReadLine();

4.3 基于特性编程模型的本质


过4.1和4.2的示例可以发现,MessageSender和Processor这两个类型就是ComposablePartDefintion的实
现,在这两个类型,我们通过Export和Import(ImportMany)特性来定义暴露的功能和引用的功能。
CompositionContainer通过这两个类所在的程序集的组件目录来搜索所有的可组合组件定义,然后在执行组合时利用这些定义创建
Export对象,根据Import声明的约束契约实现组件的组合。

在这个编程模型里面,它允许我们:(1)使用传统OOP的类型定义
来定义一个ComposablePartDefinition,毋庸置疑,这基本没有引入复杂的概念;(2)使用Export/Import
/ImportMany等元数据来声明组合功能,非常的简单且容易理解。

CompositionContainer将会在后台构建这个Part对应的ComposablePartDefinition以及组件目录其它ComposablePartDefinition,在执行组合时,利用Definition创建实例执行组合。

5 MEF vs MAF vs  Unity


刚学习MEF时,经常会问一个问题,那就是MEF和MAF这样的插件框架、和Unity这样的IoC框架到底有什么区别。MEF与MAF(Managed
Addin
Framework)最大不同在于:前者关注使用非常简单的方式来支持具有很强灵活性的可扩展支持,后者关注具有物理隔离、安全、多版本支持的插件平台架
构;MEF和Unity不同在于:前者强调组合,后者强调依赖注入。

6 MEF总结

MEF有3点让我非常的深刻,首先是组合基元的设计,其次是基于特性的编程模型,最后是MEF的实现方法。


合基元是可扩展支持的本质,它看起来显得非常的简单,但却有能够支持强大的功能能力并且不失灵活性。“大道至简”,不过,“简”的程度确实因人而
异,MEF的“简”实在让人佩服得五体投地。这个Framework也是除了ObjectBuilder之外让我非常喜欢的框架,查看其代码真是让人无比
舒畅。天人之作啊!这帮人的创新能力太强悍了!

基于特性的编程模型,允许我们使用“类的定义 + 
特性声明”的方式来定义一个具有组合能力的组件,它使得我们基于MEF编写组件变得非常非常的简单!这也让我再次体会到面向上下文编程方法的魅力~,后面
我也会介绍一下我原来做过的一个基于上下文思想设计的FW,和MEF的思路有点类似。

MEF在实现时,其顶层命名空间是
System.ComponentModel.Composition,底下划分了AttributeModel、Diagnostics、
Hosting、Primitives、ReflectionModel命名空间。MEF的顶层命名空间定义了我们使用最多的特性,底下命名空间分别用于
定义特性模型、诊断支持、MEF宿主、组合基元、反射模型,整体实现非常的清晰简洁!看第一眼我就爱上这玩意了!

7 基于特性编程模型的另一个示例


原来设计了一个基于特性的智能体编程框架。首先,我来简洁的描述什么是智能体。智能体就是软件代理人,用软件来模拟人类的特性,包括智能性、主动性、社会
性、感知性等。从实现角度来看,一个智能体就是一个绑定了线程、消息队列的对象,这个对象用线程来模拟人类大脑,用消息队列来模拟大脑记忆体。当智能体收
到一条消息时,其线程会接管来处理。根据上述描述,大家肯定觉得使用OOP开发智能体有点麻烦。OK,那下面来看看我是如何使用上下文实现智能体的。

7.1 使用特性来声明一个具有感知能力和主动性的“人”


 1 [Agent] 
 2 public class SomePerson 
 3 { 
 4     [Intelligent] 
 5     public virtual OpenTheDoor() 
 6     { 
 7         // 开门,主动性方法 
 8     }
 9     [Sensible(Environment.Temperature)] 
10     public virtual OnTemperatureChanged(SensibilityContext context) 
11     { 
12         // 当感知到温度变化的响应,感知性声明 
13     } 
14 }

7.2 创建智能体

1 var agentContainer = new AgentContainer();
2 var agent = agentContainer.Build<SomePerson>(); //在后台构建一个真正的智能体
3 agent.OpenTheDoor(); //调用OpenTheDoor方法,这个调用最终会转变成消息发送给真正的智能体由其本身来执行,就像某人让另一人去关门一样,最终将由接收到消息的人去执行关门这个动作。

AgentFramework具有和MEF类似的设计方法(当然咱们的内功和Microsoft那帮高手没得比了),通过“定义类型 + 声明智能体特性”来定义智能体,这种方式简单、灵活且可扩展性强!

体验Managed Extensibility Framework精妙的设计的更多相关文章

  1. MEF(Managed Extensibility Framework) 微软平台插件化开发

    体验Managed Extensibility Framework精妙的设计   MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要 ...

  2. MEF(Managed Extensibility Framework)有选择性地使用扩展组件

    在"MEF(Managed Extensibility Framework)使用全部扩展组件"中,客户端应用程序调用了所有的扩展组件,而且如果有新的扩展组件加入,必须先关闭程序,再 ...

  3. MEF(Managed Extensibility Framework)使用全部扩展组件

    MEF(Managed Extensibility Framework),所在命名空间是System.ComponentModel.Composition.dll.简单来说,MEF是将符合约定(一般是 ...

  4. MEF(Managed Extensibility Framework)依赖注入学习

    MSDN官方资料,并且微软还提供了SimpleCalculator sample学习样例 http://msdn.microsoft.com/en-us/library/dd460648(v=vs.1 ...

  5. 使用Managed Extensibility Framework方便的扩展应用程序

    概述 Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)以及Duck Typing等.MEF为开发 ...

  6. .Net中的插件框架Managed Extensibility Framework

    Managed Extensibility Framework(MEF)是微软的一个用来扩展.NET应用程序的框架,它最初为了满足Visual Studio里的编辑器的需求,比如说,延迟加载所有东西和 ...

  7. MEF(Managed Extensibility Framework )的入门介绍

    1.什么是MEF MEF是一个来自于微软协作构建扩展应用的新框架,它的目的是在运行中的应用中添加插件.MEF继承于.NET 4.0 Framework平台,存在于各种应用平台的系统程序集中 2.程序集 ...

  8. 12个优秀用户体验的移动应用程序 UI 设计

    最美丽的,现代化的和惊人的移动 UI 设计就在这里.今天,我们挑选了12个来自 Behance 和 Dribbble 网站的优秀用户体验的手机界面设计.这些界面设计作品都是由世界各地的优秀设计师分享, ...

  9. go web framework gin middleware 设计原理

    场景:一个middleware可以具体为一个函数,而由前面的gin 路由分析可得,每一个路径都对有一个HandlersChain 与其对应. 那么实际上增加一个middleware的过程,就是将每一个 ...

随机推荐

  1. 系统调优:如何解决系统报错too many open files

    一.检查系统版本是否手工升级 关于lsb_release -a和/etc/issue显示的发行版本号不同,原因只有一个:系统内核手动升级了 对于高并发高http连接的应用程序例如www或Java,会遇 ...

  2. 《Glibc内存管理》笔记DAY2

    目录 Ptmalloc内存管理设计 Main_arena 与 non_main_arena chunk 的组织 空闲 chunk 容器 sbrk 与 mmap 内存分配概述 内存回收概述 边界标记法 ...

  3. 最简单的SpringAop 小案例

    网盘下载地址: 链接:https://pan.baidu.com/s/1Z-em-1ouWyXeMP3JW0IbCg    提取码:0o4o 1.目录结构: 2.配置文件  applicationCo ...

  4. ubuntu dnsmasq

    /var/run/NetworkManager/resolv.conf 而你真实的dns服务器地址,是被这个服务管理维护着的/ local process -> local dnsmasq -& ...

  5. mp4文件格式解析(转)

    mp4文件格式解析 MP4文件格式带数据详解 MP4文件格式的解析,以及MP4文件的分割算法

  6. leetcode 127. Word Ladder、126. Word Ladder II

    127. Word Ladder 这道题使用bfs来解决,每次将满足要求的变换单词加入队列中. wordSet用来记录当前词典中的单词,做一个单词变换生成一个新单词,都需要判断这个单词是否在词典中,不 ...

  7. 【用户体验】Google关闭标签的体验

    https://www.uisdc.com/hunter/0221334485.html 在优设-细节猎人里有不少好案例.

  8. Go项目部署到服务器

    -bash: ./main: cannot execute binary file 将 go build main.go 生成的文件上传到服务器后,./main 运行后出新的报错 env GOOS=l ...

  9. (十三)Centos之压缩和解压缩

    一.常用压缩格式 常用压缩格式:.zip .gz .bz2 常用压缩格式:.tar.gz  .tar.bz2 二.zip格式压缩 压缩文件:zip压缩文件名 源文件 压缩目录:zip -r 压缩文件名 ...

  10. 微信小程序之对象转化为数组

    对象转成数组方式一(数组里面是一个个number类型的元素) let dictObject= { , , , , }; // 对象转成数组方式一 var createArr = [] for (let ...