使用Managed Extensibility Framework方便的扩展应用程序
概述
Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)以及Duck Typing等。MEF为开发人员提供了一个工具,让我们可以轻松的对应用程序进行扩展并且对已有的代码产生最小的影响,开发人员在开发过程中根据功能要求定义一些扩展点,之后扩展人员就可以使用这些扩展点与应用程序交互;同时MEF让应用程序与扩展程序之间不产生直接的依赖,这样也允许在多个具有同样的扩展需求之间共享扩展程序。
本文将介绍一下Managed Extensibility Framework的一些简单使用。
简单依赖注入
大家可以去这里http://code.msdn.microsoft.com/mef下载MEF的CTP版本,在下载包里有一些简单的文档和示例。下面先来看一个简单的示例,这里输出一个字符串:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
Console.WriteLine("This is a simple string.");
}
现在考虑到该字符串将来可能发生变化,不知道该字符串将从何处取得,也就是说这里有可能是一个变化点,也是一个扩展点,那我们现在使用MEF对其进行重新设计,我们将会把这个过程分成两个部分,一部分用于提供字符串,而另一部分则用来使用字符串,定义一个字符串提供程序,大家注意到这里为OutputTitle属性添加了一个Export特性,这标识着此处为一个输出,它使的MEF能够对其进行识别,如下代码所示:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class WeekStringProvider
{
[Export("Caption")]
public String OutputTitle
{
get { return "星期六"; }
}
}
这里只是定义了一个简单的属性,其实在同一个类型可以定义多个输出,Export同时指定了一个字符串的契约名称,这意味着任何匹配契约名称的程序都可以使用该扩展。除此之外,我们还可以指定一个类型来代替字符串的契约名称,后面会说到。我们再定义一个输入,即用来消费该字符串,同样是一个简单的属性,不过这次添加的是Import特性:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class Client
{
[Import("Caption")]
public String OutputTitle { get; set; }
}
现在有了输出和输入,就可以在主程序中进行调用了,需要创建一个CompositionContainer容器,并添加所有的组件到该容器中,再调用它的Bind()方法,一旦调用该方法后,就可以使用所有的组件了,如下代码所示:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
Client client = new Client(); CompositionContainer container =
new CompositionContainer(); container.AddComponent<Client>(client);
container.AddComponent<WeekStringProvider>(new WeekStringProvider());
container.Bind(); Console.WriteLine(client.OutputTitle);
}
输出结果如下图所示:
![]()
现在我们再定义另外一个扩展程序,让它返回一个日期字符串,如下代码所示:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class DateStringProvider
{
[Export("Caption")]
public String OutputTitle
{
get { return DateTime.Now.ToLongDateString(); }
}
}
修改一下组件注册程序,如下代码所示:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
Client client = new Client(); CompositionContainer container =
new CompositionContainer(); container.AddComponent<Client>(client);
container.AddComponent<DateStringProvider>(new DateStringProvider());
container.Bind(); Console.WriteLine(client.OutputTitle);
}
输出结果如下图所示:

上面的示例中我们是使用了命名契约,除此之外,还可以使用类型契约,如定义一个字符串提供者程序的接口:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public interface IStringProvider
{
String OutputTitle { get; set; }
}
现在输出和输入对应的修改为如下代码:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class DateStringProvider : IStringProvider
{
[Export(typeof(IStringProvider))]
public String OutputTitle
{
get { return DateTime.Now.ToLongDateString(); }
}
}
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class Client
{
[Import(typeof(IStringProvider))]
public String OutputTitle { get; set; }
}
运行后可以看到它与前面的示例效果是一样的。
Duck Typing支持
了解DI的朋友可能都有这样的疑问,其实上面的代码就是一个依赖注入,微软模式与实践团队已经开发出了Unity,为什么还需要一个MEF呢?其实MEF的定位并不是DI,在前面我已经说过,它主要是用于应用程序扩展管理,下面我们再看一个示例,它在这方面具有什么样的优势,看下面这段代码:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
[ContractType("TerryLeeCalculatro")]
public interface ICalculator
{
int Execute(int x, int y);
} public class Client
{
[Import(typeof(ICalculator))]
public ICalculator Calculator { get; set; }
}
这里我们定义了一个输入,它里面具有一个ICalculator的属性,也就是说它需要的输入是一个类型是ICalculator的实例。现在我们定义输出,如下代码所示:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
[Export(typeof(ICalculator))]
public class SubCalculator : ICalculator
{ public int Execute(int x, int y)
{
return x - y;
}
}
在主函数中进行调用:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
Client client = new Client(); CompositionContainer container =
new CompositionContainer(); container.AddComponent<Client>(client);
container.AddComponent<SubCalculator>(new SubCalculator());
container.Bind(); Console.WriteLine(client.Calculator.Execute(1,2));
}
输出结果如下图所示:

现在我们需要对该程序扩展,让其计算结果为两个数相加,如果使用DI,我们可能会想到,再编写一个支持加法计算的类,让其实现ICalculator接口,然而这里我们重新定义了一个新的接口IMyCalculator:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
[ContractType("TerryLeeCalculatro")]
public interface IMyCalculator
{
int Execute(int x, int y);
} [Export(typeof(IMyCalculator))]
public class AddCalculator : IMyCalculator
{ public int Execute(int x, int y)
{
return x + y;
}
}
这里重新定义了一个新接口IMyCalculator,我们为它设置的契约类型和前面定义的接口ICalculator一致。而AddCalculator实现这个接口,同样用Export标识它为一个输出。最后调用程序如下:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
Client client = new Client(); CompositionContainer container =
new CompositionContainer(); container.AddComponent<Client>(client);
container.AddComponent<AddCalculator>(new AddCalculator());
container.Bind(); Console.WriteLine(client.Calculator.Execute(1,2));
}
输出结果如下图所示:

大家可能已经意识到了,上面示例中的输入需要ICalculator类型,而我们扩展的输出却是IMyCalculator类型,它仅仅是与ICalculator标识为相同的契约类型,这种方式带来了极大的灵活性,也就是说我们在对原有应用程序进行扩展时,并不需要与原有应用程序产生任何依赖,可以独立的进行扩展。
Plug-In支持
在前面的例子中,始终有一个问题没有解决,就是当每次编写一个扩展程序后,都需要修改代码向CompositionContainer中注册组件,这样其实并没有实现真正的扩展,我们希望的扩展是Plug-In机制。在MEF对于Plug-In提供了很好的支持,它提供了DirectoryWatchingComponentCatalog类来对指定的目录进行监视,就是说我们定义好了输入之后,只要把相关的输出组件放在指定目录中,MEF会通过反射来进行自动查找,如我们定义这样的一个输入:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class User
{
[Import("Role")]
public String Role { get; set; }
}
现在定义输出,我们把它放在一个单独的类库项目中:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class DatabaseProvider
{
[Export("Role")]
public String AvailableRole
{
get { return "Developer"; }
}
}
在主调用程序的目录下,我们创建一个Extensions的目录,然后把相关的扩展组件都放在该目录下,并在主调用程序中,为DirectoryWatchingComponentCatalog实例加入Extensions目录,这样就避免了与具体的扩展应用程序产生依赖,如下代码所示:
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
static void Main(string[] args)
{
User user = new User(); DirectoryWatchingComponentCatalog catalog =
new DirectoryWatchingComponentCatalog();
catalog.AddDirectory(@"Extensions"); CompositionContainer container = new CompositionContainer(catalog.Resolver);
container.AddComponent<User>(user);
container.Bind(); Console.WriteLine(user.Role);
Console.ReadLine();
}
运行后输出结果如下:

对于MEF来说,Duck Typing支持以及Plug-In支持才是它的优势所在,它不是一个简单的DI容器,而是一个真正的管理扩展框架。当然了现在MEF还处于CTP阶段,很多功能还不是很完善。在8月初,微软还特意请到了Castle之父Hammett加入该项目组,担任Program Manager,MEF的未来值得期待,更值得期待的是MEF将会为Silverlight应用程序开发一个MEF子集,让我们对于Silverlight程序也能够方便的进行扩展。
Managed Extensibility Framework的官方主页是:http://code.msdn.microsoft.com/mef。
总结
本文简单介绍了Managed Extensibility Framework的一些使用,希望对大家有所帮助。
出处:http://www.cnblogs.com/Terrylee/archive/2008/09/01/uisng-managed-extensibility-framework-overview.html
=================================================================================================
就在几天前,我写了一篇关于Managed Extensibility Framework(MEF)的文章《使用Managed Extensibility Framework方便的扩展应用程序》,有一位朋友提到MEF为什么不在codeplex上,而当时我的回答是不放在Codeplex上是因为它现在还不开源,所以只能放在http://code.msdn.microsoft.com上了。然而,还不到一周的时间,微软就在Codeplex上开放了全部的源码,以及相关的文档等。

出处:https://www.cnblogs.com/Terrylee/archive/2008/09/08/microsoft-extensibility-framework-released-on-codeplex.html
使用Managed Extensibility Framework方便的扩展应用程序的更多相关文章
- MEF(Managed Extensibility Framework)使用全部扩展组件
MEF(Managed Extensibility Framework),所在命名空间是System.ComponentModel.Composition.dll.简单来说,MEF是将符合约定(一般是 ...
- MEF(Managed Extensibility Framework)有选择性地使用扩展组件
在"MEF(Managed Extensibility Framework)使用全部扩展组件"中,客户端应用程序调用了所有的扩展组件,而且如果有新的扩展组件加入,必须先关闭程序,再 ...
- MEF(Managed Extensibility Framework) 微软平台插件化开发
体验Managed Extensibility Framework精妙的设计 MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要 ...
- .Net中的插件框架Managed Extensibility Framework
Managed Extensibility Framework(MEF)是微软的一个用来扩展.NET应用程序的框架,它最初为了满足Visual Studio里的编辑器的需求,比如说,延迟加载所有东西和 ...
- 体验Managed Extensibility Framework精妙的设计
MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要的库,Visual Studio 2010 Code Editor的扩展支持也是基 ...
- MEF(Managed Extensibility Framework)依赖注入学习
MSDN官方资料,并且微软还提供了SimpleCalculator sample学习样例 http://msdn.microsoft.com/en-us/library/dd460648(v=vs.1 ...
- MEF(Managed Extensibility Framework )的入门介绍
1.什么是MEF MEF是一个来自于微软协作构建扩展应用的新框架,它的目的是在运行中的应用中添加插件.MEF继承于.NET 4.0 Framework平台,存在于各种应用平台的系统程序集中 2.程序集 ...
- 如何用 MEF 扩展应用程序
最近在写一篇关于如何扩展 Visual Studio 编辑器的文章时,用到了 MEF,因此打算写一篇文章提一下这个技术点.本篇文章并不打算详细介绍 MEF,只是一个最简单的入门,相信您在阅读本篇文章后 ...
- Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->使用Spring Framework开发自己的应用程序
1.直接基于spring framework开发自己的应用程序: 1.1参考资料: Spring官网spring-framework.4.3.5.RELAESE的Reference Documenta ...
随机推荐
- 3.1 C++继承的概念及语法
参考:http://www.weixueyuan.net/view/6358.html. 总结: 继承可以理解为一个类从另一个类获取方法(函数)和属性(成员变量)的过程. 被继承的类称为父类或基类,继 ...
- 线程安全的集合类、CopyOnWrite机制介绍(转)
看过并发编程的书,这两种机制都有所了解,但不扎实其实.看到别人的博客描述的很精辟,于是转过来,感谢! 原文链接:https://blog.csdn.net/yen_csdn/article/detai ...
- 实力封装:Unity打包AssetBundle(三)
前情提要:第二种打包方式 窗口初现 通过前面的两篇教程和一篇番外,我们已经完全实现了打包的功能.但是使用起来总是觉得有些晦涩别扭,如果不告诉别人怎么使用,对方肯定是一头雾水. What?你给我的这是啥 ...
- 再谈kbmMW垃圾回收
很早就写了关于kbmMW Server如何实现的垃圾回收,但最近一段时间还是为此遇到问题,实现的Server不能稳定运行,发生问题后不响应客户端的查询请求,在客户端得到服务端返回地址错误信息,只能重启 ...
- Kaggle(1):数据挖掘的基本流程
我觉得做任何事情,一定要有章法.对于学习类的事情,就是要有框架.第一次打Kaggle比赛,我的一个重要收获就是初步搞清楚了打这类比赛的框架. 可以分为以下六步:理解问题.分析问题.算法选择.结果评价. ...
- Window下部署Maven Nexus
Nexus下载地址:https://www.sonatype.com/download-oss-sonatype 选择相应的版本下载后,本人下载的是nexus-2.12.0-01-bundle.zip ...
- 2.20 绕过验证码(add_cookie)
2.20 绕过验证码(add_cookie) 前言验证码这种问题是比较头疼的,对于验证码的处理,不要去想破解方法,这个验证码本来就是为了防止别人自动化登录的.如果你能破解,说明你们公司的验证码吗安全级 ...
- php实现弱语言底层原理分析(转)
php中弱语言类型的底层实现 PHP是弱语言类型,主要分为三类: 1.标量类型:integer.string.float.boolean 2.复合类型:array.object 3.特殊类型:reso ...
- Python之路,第四篇:Python入门与基础4
Python3 字符串 字符串是一个有序的字符序列 如何表示一个字符串: 在非注释中凡是用引号括起来的部分都是字符串: ‘ 单引号 ” 双引号 ‘’‘ 三单引号 “”“ ...
- CentOS7为firewalld添加开放端口及相关操作
1.firewalld的基本使用 启动: systemctl start firewalld 查看状态: systemctl status firewalld 停止: systemctl disabl ...