使用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 ...
随机推荐
- springmvc添加定时任务
springmvc.xml文件中添加如下配置 <bean id="ClearTempRoomLogTask" class="com.test.listener.St ...
- Ansible-playbook的简单使用 [转]
一. 介绍 ansbile-playbook是一系列ansible命令的集合,利用yaml 语言编写.playbook命令根据自上而下的顺序依次执行.同时,playbook开创了很多特性,它可以允许你 ...
- Highcharts 柱图 每个柱子外围的白色边框
Highcharts 柱图中每条柱外会有默认白色的边框, 去边框代码如下: plotOptions: { bar: { borderColor: "",//去边框 } }
- <Parquet><Physical Properties><Best practice><With impala>
Parquet Parquet is a columnar storage format for Hadoop. Parquet is designed to make the advantages ...
- nginx——ngx_http_gzip_module
文件压缩 Syntax: gzip on | off; Default: gzip off; Context: http, server, location, if in location Synta ...
- python 字典,列表,集合,字符串,基础进阶
python列表基础 首先当然是要说基础啦 列表list 1.L.append(object) -> None 在列表末尾添加单个元素,任何类型都可以,包括列表或元组等 2.L.extend(i ...
- centos 安装thrift
Thrift介绍 Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erl ...
- 九度OJ1451题-信封错装
题目1451:不容易系列之一 时间限制:1 秒 内存限制:128 兆 特殊判题:否 提交:2004 解决:1210 题目描述: 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了!做好“ ...
- supervisor-program配置
[program:check_server_state]directory=/sunlight/shellcommand=/usr/bin/sh check_server_state.shautost ...
- Unity 3D观察者设计模式-C#委托和事件的运用
C#观察者设计模式 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享.心创新! ...