在过去,我们完成一套应用程序后,如果后面对其功能进行了扩展或修整,往往需要重新编译代码生成新的应用程序,然后再覆盖原来的程序。这样的扩展方式对于较小的或者不经常扩展和更新的应用程序来说是可以接受的,而对于像ERP系统那样复杂而且常常需要扩展的应用程序,这种扩展方法就不够方便,因为每次都要修改源代码或重新引用组件。

尤其是组件(许多dll),如果每编写一个新组件又要在主项目中引用一次,显然主项目就不得不经常重新生成。要是能有一种机制,可以在主项目应用程序不作任何修改就可以自动识别并扩展组件,就会很便捷,我们每次扩展只需要更新或者添加某些dll文件即可。

MEF正是为了解决上述问题而诞生。MEF全称Managed Extensibility Framework,至于如何翻译不重要,你喜欢怎么个译法都无所谓,我们只要明白它用来干啥就好了。

宽泛的理论似乎作用不明显,我们还是先来弄一个简单的例子。现在假设我在开发一个应用程序,首先我要为一些组件以及将来可以要扩展的组件定义公共接口(或者说是协定,大家是否记得在WCF中也是这样,先定义一些公共的服务协定,然后视具体情况对这些协定进行扩展),然后我可以按照不同的情形去实现这些接口,这也是我们常说的,接口可以起到规范作用,有了规范,正是为后期扩展打下可行性基础。

例子的主项目是一个控制台应用程序,我们先在解决方案中添加一个类库项目,为了简单演示,我定义了以下接口:

public interface IExtBase

 { 

void DoTask(); 

string TaskName { get; } 

 }

这个IExtBase接口就作为我们要扩展的组件的公共协定,不管我以后怎么扩展,哪怕我要添加100000个组件,这些组件都要实现IExtBase接口。

这里我做了两个扩展作为例子,为了表明MEF框架能自动发现组件,我把两个实现IExtBase接口的类写到另外一个类库项目中——TaskToa.dll。

[Export("task1", typeof(CommExtBase.IExtBase))] 

public class Task_1 : CommExtBase.IExtBase

 { 

public void DoTask() 

 { 

Console.WriteLine("任务1执行。"); 

 } 

public string TaskName 

 { 

get

 { 

return "任务1"; 

 } 

 } 

 } 

 [Export("task2", typeof(CommExtBase.IExtBase))] 

public class Task_2 : CommExtBase.IExtBase

 { 

public void DoTask() 

 { 

Console.WriteLine("任务2执行。"); 

 } 

public string TaskName 

 { 

get { return "任务2"; } 

 } 

 }

附加ExportAttribute特性用于扩展的组件类,表示它们将被导出,导出的类型会被MEF自动发现。

在主项目中我们不引用这个TaskToa类库,先把TaskToa项目生成一个TaskToa.dll,直接复制到.exe应用程序的动行目录下,在调试模中为\\项目\\bin\\Debug目录下。

由于实现公共接口的类不止一个,后续可能还有10000000个,为了能够使所有的扩展组件都能被发现,统一的协定类型为IExtBase接口(与WCF的实现服务协定相似),在附加ExportAttribute特性时指定了每个组件类的协定名,而协定类型都是IExtBase接口,协定类型必须统一才能保证所有扩展的类能被MEF框架发现。

最后在.exe主项目的代码中加入以下代码:

using System; 

using System.Collections.Generic; 

using System.Linq; 

using System.Text; 

using System.Threading.Tasks; 

using System.ComponentModel.Composition; 

using System.ComponentModel.Composition.Hosting; 

namespace MainApp 

{ 

class TestWork

 { 

 [Import("task1")] 

public CommExtBase.IExtBase Task1; 

 [Import("task2")] 

public CommExtBase.IExtBase Task2; 

 } 

class Program

 { 

static void Main(string[] args) 

 { 

ApplicationCatalog appCat = new ApplicationCatalog(); 

CompositionContainer container = new CompositionContainer(appCat); 

TestWork tw = new TestWork(); 

try

 { 

 container.ComposeParts(tw); 

Console.WriteLine("Task1的类型:{0}\tTaskName: {1}\t调用DoTask方法:",tw.Task1.GetType().Name,tw.Task1.TaskName); 

 tw.Task1.DoTask(); 

Console.Write("\n\n"); 

Console.WriteLine("Task2的类型:{0}\tTaskName:{1}\t调用DoTask方法:", 

tw.Task2.GetType().Name, tw.Task2.TaskName); 

 tw.Task2.DoTask(); 

 } 

catch (CompositionException cex) 

 { 

Console.WriteLine(cex.Message); 

 } 

Console.Read(); 

 } 

 } 

} 

TestWork类用来包装最后被合并的组件,它有两个公共字段,类型虽然都是IExtBase,但由于应用了ImportAttribute特性,并且指定了协定名,这些协定名一定要与我们之前在扩展类中应用ExportAttribute是指定的协定名相对应。附加了ImportAttribute特性可以让MEF识别对应的组件并导入到TestWork类中。

在Main入口点中,我们先使用ApplicationCatalog类来收集所有可用的扩展组件,然后把收集到的信息传给CompositionContainer容器,容器负责把收集到的组件进行合并(组装)。合并完成后我们就可以使用这些组件了。

本例子的运行结果如下面的截图所示:

从截图中我们看到,TestWork类的Task1和Task2字段的类型分别为Task_1和Task_2,同时也调用了它们的成员,输出结果表明,我们之前开发的两个扩展类Task_1和Task_2已经自动导入到我们当前的应用程序中了。

ApplicationCatalog类是在当前应用程序的运行目录下查找所有符合要求的exe或dll中的扩展组件,一旦找到就自动收集并生成组件目录,而后提供给CompositionContainer进行组装。

从这个例子我们看到MEF框架就像一个大型的组装厂车间,首先设计师们寻找灵感,构思产品的基本模型,这也就是我们所定义的公共接口规范;随后,进行精确计算,进一步把抽象的模型变为具体的工程图,这相当于我们自己实现编写的各个扩展类;接着,相关工作人员会把设计师和工程师做好的各个零部件的工程图收集整理,准备提供给车间进行生产组装,这就相当于我们例子中的ComposablePartCatalog,我们例子中用到的ApplicationCatalog只是其中一个收集方式,其他的方式还有按程序集进行收集或按特定路径目录下的所有类库进行收集。然后车间开始制作并组装成产品,最终投入使用。

我们可以用下面的图来描述一下整个过程(此图纯属虚构,如有雷同,实属巧合)

现在我们先不必过多关注代码细节,因为后面我会慢慢介绍,我们只要明白MEF的用途就可以了。

OK,本文就说到这里吧,88

实战MEF(1):一种不错的扩展方式的更多相关文章

  1. 实战MEF(1)一种不错的扩展方式

    在过去,我们完成一套应用程序后,如果后面对其功能进行了扩展或修整,往往需要重新编译代码生成新的应用程序,然后再覆盖原来的程序.这样的扩展方式对于较小的或者不经常扩展和更新的应用程序来说是可以接受的,而 ...

  2. Jenkins持续集成企业实战系列之两种网站部署的流程-----01

    注:原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.    最初接触Jenkins也是由于公司需求,根据公司需求Java代码项目升级的.(公司是 ...

  3. 两种不同的扩展Scrum的方式

    两种不同的扩展Scrum的方式 1.LeSS和LeSS Huge –大型Scrum LeSS(和LeSS Huge –真正的大型程序)的合著者Craig Larman首先批评了管理,开发人员和客户传统 ...

  4. 实战MEF(4):搜索范围

    在前面的文章中,几乎每个示例我们都会接触到扩展类的搜索位置,我们也不妨想一下,既然是自动扩展,它肯定会有一个或者多人可供查找的位置,不然MEF框架怎么知道哪里有扩展组件呢? 就像我们用导航系统去查找某 ...

  5. 实战MEF(2):导出&导入

    上一文中,我们大致明白了,利用MEF框架实现自动扫描并组装扩展组件的思路.本文我们继续前进,从最初的定义公共接口开始,一步步学会如何使用MEF. 在上一文中我们知道,对于每一个实现了公共规范的扩展组件 ...

  6. jQuery插件主要有两种扩展方式

    jQuery插件主要有两种扩展方式: 扩展全局函数方式. 扩展对象方法方式. 扩展全局函数方式 扩展全局函数方式定义的插件,即类级别插件,可以通过jQuery.extend()来进行定义.定义格式为: ...

  7. Yii实战中8个必备常用的扩展,模块和widget

    Yii实战中8个必备常用的扩展,模块和widget 在经过畅K网 的实战后,总结一下在Yii的项目中会经常用到的组件和一些基本的使用方法,分享给大家,同时也给自己留个备忘录,下面我以代码加图片说明. ...

  8. 三种Tomcat集群方式的优缺点分析

    三种Tomcat集群方式的优缺点分析 2009-09-01 10:00 kit_lo kit_lo的博客 字号:T | T 本文对三种Tomcat集群方式的优缺点进行了分析.三种集群方式分别是:使用D ...

  9. http 3种web会话管理方式

    http是无状态的,一次请求结束,连接断开,下次服务器再收到请求,它就不知道这个请求是哪个用户发过来的.当然它知道是哪个客户端地址发过来的,但是对于我们的应用来说,我们是靠用户来管理,而不是靠客户端. ...

随机推荐

  1. 基于孪生卷积网络(Siamese CNN)和短时约束度量联合学习的tracklet association方法

    基于孪生卷积网络(Siamese CNN)和短时约束度量联合学习的tracklet association方法 Siamese CNN Temporally Constrained Metrics T ...

  2. 如何让eclipse进行智能提示?

    1.打开eclipse工具,点击window菜单,选择preferences选项 2.然后,选择Java->Editor->content assist 3.然后在Auto activat ...

  3. 整理 PHPstorm实用个人配置,修改调整个性化快捷键,修改使用phpstorm创建的模板的默认注释:

    对你有助请点赞,请顶------送人玫瑰,手留余香! 1:58 2016/3/12 整理PHPstorm实用个人配置,修改调整个性化快捷键,修改使用phpstorm创建的模板的默认注释: PHPsto ...

  4. Android 学习笔记之二——开启闪光灯

    今天想写个手电筒应用,看网上的代码基本都是如下: camera = Camera.open(); parameters = camera.getParameters(); parameters.set ...

  5. HTTP请求与响应

    HTTP协议是超文本传输协议的所写,它是TCP/IP协议的一个应用层协议,用于定义web浏览器和web服务器之间交换数据的过程. TCP/IP协议的应用层协议还有POP3等协议 一.HTTP请求 (一 ...

  6. Java技术体系图

    Java程序员高级特性              反射.泛型.注释符.自动装箱和拆箱.枚举类.可变              参数.可变返回类型.增强循环.静态导入        核心编程       ...

  7. Spring的三种通过XML实现DataSource注入方式

    Spring的三种通过XML实现DataSource注入方式: 1.使用Spring自带的DriverManagerDataSource 2.使用DBCP连接池 3.使用Tomcat提供的JNDI

  8. 基于webdriver的jmeter性能测试-Selenium IDE

    前言: 由于某些项目使用了WebGL技术,需要高版本的Firefox和Chrome浏览器才能支持浏览,兼容性很弱,导致Loadrunner和jmeter(badboy)无法正常进行录制脚本.因此我们采 ...

  9. Smart3D系列教程1之《浅谈无人机倾斜摄影建模的原理与方法》

    一.引言 倾斜摄影测量技术是国际测绘遥感领域近年发展起来的一项高新技术,以大范围.高精度.高清晰的方式全面感知复杂场景,通过高效的数据采集设备及专业的数据处理流程生成的数据成果直观反映地物的外观.位置 ...

  10. spark 你要喧宾夺主么?好好干。

    嗯嗯,hadoop EcoSystem.