概述

Managed Extensibility Framework(MEF)是.NET平台下的一个扩展性管理框架,它是一系列特性的集合,包括依赖注入(DI)以及Duck Typing等。MEF为开发人员提供了一个工具,让我们可以轻松的对应用程序进行扩展并且对已有的代码产生最小的影响,开发人员在开发过程中根据功能要求定义一些扩展点,之后扩展人员就可以使用这些扩展点与应用程序交互;同时MEF让应用程序与扩展程序之间不产生直接的依赖,这样也允许在多个具有同样的扩展需求之间共享扩展程序。

本文将介绍一下Managed Extensibility Framework的一些简单使用。

简单依赖注入

大家可以去这里http://code.msdn.microsoft.com/mef下载MEF的CTP版本,在下载包里有一些简单的文档和示例。下面先来看一个简单的示例,这里输出一个字符串:

Code 1
// 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能够对其进行识别,如下代码所示:

Code 2
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class WeekStringProvider
{
[Export("Caption")]
public String OutputTitle
{
get { return "星期六"; }
}
}

这里只是定义了一个简单的属性,其实在同一个类型可以定义多个输出,Export同时指定了一个字符串的契约名称,这意味着任何匹配契约名称的程序都可以使用该扩展。除此之外,我们还可以指定一个类型来代替字符串的契约名称,后面会说到。我们再定义一个输入,即用来消费该字符串,同样是一个简单的属性,不过这次添加的是Import特性:

Code 3
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class Client
{
[Import("Caption")]
public String OutputTitle { get; set; }
}

现在有了输出和输入,就可以在主程序中进行调用了,需要创建一个CompositionContainer容器,并添加所有的组件到该容器中,再调用它的Bind()方法,一旦调用该方法后,就可以使用所有的组件了,如下代码所示:

Code 4
// 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);
}

输出结果如下图所示:

现在我们再定义另外一个扩展程序,让它返回一个日期字符串,如下代码所示:

Code 5
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class DateStringProvider
{
[Export("Caption")]
public String OutputTitle
{
get { return DateTime.Now.ToLongDateString(); }
}
}

修改一下组件注册程序,如下代码所示:

Code 6
// 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);
}

输出结果如下图所示:

上面的示例中我们是使用了命名契约,除此之外,还可以使用类型契约,如定义一个字符串提供者程序的接口:

Code 7
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public interface IStringProvider
{
String OutputTitle { get; set; }
}

现在输出和输入对应的修改为如下代码:

Code 8
// 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(); }
}
}
Code 9
// 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,在前面我已经说过,它主要是用于应用程序扩展管理,下面我们再看一个示例,它在这方面具有什么样的优势,看下面这段代码:

Code 10
// 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的实例。现在我们定义输出,如下代码所示:

Code 11
// 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;
}
}

在主函数中进行调用:

Code 12
// 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:

Code 13
// 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标识它为一个输出。最后调用程序如下:

Code 14
// 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会通过反射来进行自动查找,如我们定义这样的一个输入:

Code 15
// Author: TerryLee 2008.8.30
// URL: http://www.cnblogs.com/Terrylee
public class User
{
[Import("Role")]
public String Role { get; set; }
}

现在定义输出,我们把它放在一个单独的类库项目中:

Code 16
// 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目录,这样就避免了与具体的扩展应用程序产生依赖,如下代码所示:

Code 17
// 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上开放了全部的源码,以及相关的文档等。

MEF主页:http://www.codeplex.com/MEF

出处:https://www.cnblogs.com/Terrylee/archive/2008/09/08/microsoft-extensibility-framework-released-on-codeplex.html

使用Managed Extensibility Framework方便的扩展应用程序的更多相关文章

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

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

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

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

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

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

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

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

  5. 体验Managed Extensibility Framework精妙的设计

    MEF(Managed Extensibility Framework)是.NET Framework 4.0一个重要的库,Visual Studio 2010 Code Editor的扩展支持也是基 ...

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

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

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

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

  8. 如何用 MEF 扩展应用程序

    最近在写一篇关于如何扩展 Visual Studio 编辑器的文章时,用到了 MEF,因此打算写一篇文章提一下这个技术点.本篇文章并不打算详细介绍 MEF,只是一个最简单的入门,相信您在阅读本篇文章后 ...

  9. Spring Framework------>version4.3.5.RELAESE----->Reference Documentation学习心得----->使用Spring Framework开发自己的应用程序

    1.直接基于spring framework开发自己的应用程序: 1.1参考资料: Spring官网spring-framework.4.3.5.RELAESE的Reference Documenta ...

随机推荐

  1. 无法卸载Sql Server 的解决办法

    提示如下: 解决办法: 命令提示符——>wmic——>product list 找到与Sql Server 有关的程序: 重新打开一个命令提示符: 执行卸载命令:msiexec /x {7 ...

  2. python常见面试题(mark)

    1.大数据的文件读取 ① 利用生成器generator ②迭代器进行迭代遍历:for line in file 2.迭代器和生成器的区别 1)迭代器是一个更抽象的概念,任何对象,如果它的类有next方 ...

  3. java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result异常的解决方法

    今天在写一个JAVA程序的时候出现了异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact repr ...

  4. 在嵌入式设计中使用MicroBlaze(Vivado版本)(转)

    原文Xilinx官方文档<ug898-vivado-embedded-design>第三章 一.MicroBlaze处理器设计介绍(略) 二.创建带有MicroBlaze处理器的IP设计 ...

  5. 第三节 java 数组

    一维数组: 同一种类型数据的集合,其实数组就是一个容器. 好处: 可以自动给数组中的元素从0开始编号,方便操作这些元素. 格式1: 元素类型[]  数组名 = new 元素类型 [元素个数或者元素长度 ...

  6. DevExpress v18.1新版亮点——CodeRush for VS篇(二)

    用户界面套包DevExpress v18.1日前正式发布,本站将以连载的形式为大家介绍各版本新增内容.本文将介绍了CodeRush for Visual Studio v18.1 的新功能,快来下载试 ...

  7. tf多线程读取数据

    多线程读取数据的机制 tf中多线程读取数据跟常规的python多线程思路一致,是基于Queue的多线程编程. 主线程读取数据,然后计算,在读数据这部分有两个线程,一个线程读取文件名,生成文件名队列,另 ...

  8. Linux文件系统命令 ls

    名称:ls 功能:查看文件列表 renjg@renjg-HP-Compaq-Pro--MT:~$ ls add-on.yaml Desktop examples.desktop meta-gnome3 ...

  9. 20165326 java第六周学习笔记

    第六周学习总结 ch8 String类对于有效处理字符序列信息非常重要. String对象的字符序列不能被修改删除,无法发生变化. StringBuffer类的对象实体的内存空间可以自动改变大小,便于 ...

  10. 20165326 java第二周学习笔记

    学习笔记 一.理论学习 基本数据类型与数组 标识符的第一个字符不能是数字:标识符不能为关键字. 基本数据类型多数与c语言相同.重点如下: 1.逻辑类型boolean赋值true/false 2.浮点数 ...