MEF——.NET中值得体验的精妙设计

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>。这个表达式用于对一个ExportDefintion做匹配判定,其匹配方法如下:

  以下是代码片段:

1. var allExportDefs = …// 从ComposablePartCatalog获取所有ExportDefinition
2. var constraintDelegate= Constraint.Compile(); //编译成匹配函数的代理
3. 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 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(); //在后台构建一个真正的智能体
3. agent.OpenTheDoor(); //调用OpenTheDoor方法,这个调用最终会转变成消息发送给真正的智能体由其本身来执行,就像某人让另一人去关门一样,最终将由接收到消息的人去执行关门这个动作。

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

时间: 2024-10-26 02:14:37

MEF——.NET中值得体验的精妙设计的相关文章

MEF——.NET中值得体验的精妙设计(转)

MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要的库,Visual Studio 2010 Code Editor的扩展支持也是基于MEF构建的.MEF的目标是简化创建可扩展的应用程序,其核心类是ComposablePart,即具有组合能力的组件,每一个称为ComposablePart(中文可为可组合构件,不过下文一直采用英文来表示,这样比较贴切)的组件可以组合(称为Import)其它组件的功能(其它组件通过声明Export提

.NET中值得体验的精妙设计

转自: http://developer.51cto.com/art/201104/255455_all.htm .NET 是 Microsoft XML Web services 平台.MEF是.NET Framework 4.0一个重要的库,Visual Studio 2010 Code Editor的扩展支持也是基于MEF构建的.下面让我们一起来看. MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要的库,Visual S

【转载】20个2013年最值得关注的网页设计趋势

原博文地址:http://ued.lanrentuku.com/di/2013wangyeshejiqushi.html 在过去的一年中,我们都看到了网页设计趋势在日益增长.或许有些朋友还记得我早些时候的一些文章关于网页设计,有兴趣的可以点击来查看,现在我们可以看到其中许多想法已经实现了,甚至有些采用了一些更高层次的新奇想法.在今天这篇文章中,我将与大家分享2013年里20多种网页设计的全新趋势走向. 设计的影响仅仅是一个来自于我们的文化和用户界面感知的反馈.观念上这些趋势代表了在网页设计社区最

中后台产品的表格设计,看这一篇就够了(原型规范下载)

中后台产品的表格设计,看这一篇就够了(原型规范下载) 2018年4月16日luodonggan 中后台产品的表格设计,看这一篇就够了(原型规范下载) 经过了将近一年的后台产品经历,踩了很多坑,试了很多错,也学习到了很多东西,目前也形成了自己的一套规范.本文将其中的部分收获汇总成文,希望能够对大家有所帮助. 后台产品有一个很重要.常见的元素,就是表格.表格承担着详情入口.数据展示的功能,看似简单,其实里面的细节特别多.在以效率为最重要的需求的后台产品中,如何设计一个能够高效率地进行查看和编辑的表格

C++11 中值得关注的几大变化(网摘)

C++11 中值得关注的几大变化(详解) 原文出处:[陈皓 coolshell] 源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 (and Why You Should Care),赖勇浩做了一个中文翻译在这里.所以,我就不翻译了,我在这里仅对文中提到的这些变化"追问为什么要引入这些变化"的一个探讨,只有知道为了什么,用在什么地方,我们才能真正学到这个知识.而以此你可以更深入地了解这些变化.所以,本文不是翻译.因为写

中软国际教育UI设计:2017年UI设计就业前景趋势

随着计算机的普及应用,人们对计算机的要求越来越高,从而衍生了诸多计算机行业,比如编程类.美工类.硬件类等等.那么今天软妹子就给各位剖析UI设计师就业前景. 移动互联网的发展带动了UI设计行业的兴起, 目前UI即用户界面设计行业刚刚在全球软件业兴起,属于高新技术设计产业,与国外在同步发展水平. 国内大型互联网企业越来越注重网站和产品的交互设计及用户体验,UI 设计必将越来越火,目前国内外一批互联网巨头企业,如腾讯.YAHOO.中国移动.联想.网易.华为.中软.微软.盛大.淘宝等纷纷成立了 UI 设

体验引擎游戏设计全景探秘——互动出版网

这篇是计算机类的优质首发推荐>>>><体验引擎游戏设计全景探秘> 腾讯副总裁及魔方.蜜獾两大工作室老总作序推荐 基于玩家体验设计游戏第一书 同时覆盖规划.平衡性.界面.营销诸要素 编辑推荐 你是否已经准备好大幅提升自己的游戏设计功力?本书不但会让你眼前一亮,而且会帮助你对市面上许多游戏大作的设计结构一探究竟.你将学习和接触到许多有关游戏制作的原理和实践,通过这些原理和实践将会产生情感丰富的游戏体验,包括各种优雅的游戏机制,引人入胜的虚构元素,以及如何掌控节奏使得玩家获得

Java生鲜电商平台-电商中海量搜索ElasticSearch架构设计实战与源码解析

Java生鲜电商平台-电商中海量搜索ElasticSearch架构设计实战与源码解析 生鲜电商搜索引擎的特点 众所周知,标准的搜索引擎主要分成三个大的部分,第一步是爬虫系统,第二步是数据分析,第三步才是检索结果.首先,电商的搜索引擎并没有爬虫系统,因为所有的数据都是结构化的,一般都是微软的数据库或者 Oracle 的数据库,所以不用像百度一样用「爬虫」去不断去别的网站找内容,当然,电商其实也有自己的「爬虫」系统,一般都是抓取友商的价格,再对自己进行调整. 第二点,就是电商搜索引擎的过滤功能其实比

微软BI 之SSRS 系列 - 实现 Excel 中图表结合的报表设计

来自群里面讨论的一个问题,EXCEL 中有类似于这样的图形,上面是 Chart, Chart X轴上的值正好就是下方 Table 的列头,这个在 SSRS 中应该如何实现? SSRS 2008.2008RS,2012 中实际上没有这种对应的控件,我们通常想到的方式可能是上方一个单独的 Chart 图,下方一个 Table 然后合并在一起.但是这样会存在一些问题,因为 Chart 轴的值不是固定的,会随着聚合值的增加而扩展.并且对于表中的列头来说也没有办法完全能够和 Chart X 轴上的坐标对应