概述

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

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

简单依赖注入

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

Code 1
 
 static voidMain(string[] args) {      Console.WriteLine("This is a simple string.");}

现在考虑到该字符串将来可能发生变化,不知道该字符串将从何处取得,也就是说这里有可能是一个变化点,也是一个扩展点,那我们现在使用MEF对其进行重新设计,我们将会把这个过程分成两个部分,一部分用于提供字符串,而另一部分则用来使用字符串,定义一个字符串提供程序,大家注意到这里为OutputTitle属性添加了一个Export特性,这标识着此处为一个输出,它使的MEF能够对其进行识别,如下代码所示:

Code 2
 
public class WeekStringProvider    {         [Export("Caption")] public String OutputTitle         { get { return "星期六"; }         }     }

 

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

Code 3
 
 public class Client     {         [Import("Caption")] public String OutputTitle         { get; set; }     }

 

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

Code 4
 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
 
 public class DateStringProvider   {       [Export("Caption")] public String OutputTitle       { get { return DateTime.Now.ToLongDateString(); }      }   }

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

Code 6
 
 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
 public interface IStringProvider  { String OutputTitle { get; set; } }

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

Code 8
  public class DateStringProvider : IStringProvider      {          [Export(typeof(IStringProvider))] public String OutputTitle          {get { return DateTime.Now.ToLongDateString(); }         }      }

Code 9
 public class Client       {           [Import(typeof(IStringProvider))] public String OutputTitle           { get; set; }       }

运行后可以看到它与前面的示例效果是一样的。

Duck Typing支持

了解DI的朋友可能都有这样的疑问,其实上面的代码就是一个依赖注入,微软模式与实践团队已经开发出了Unity,为什么还需要一个MEF呢?其实MEF的定位并不是DI,在前面我已经说过,它主要是用于应用程序扩展管理,下面我们再看一个示例,它在这方面具有什么样的优势,看下面这段代码:

Code 10
[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
[Export(typeof(ICalculator))]public class SubCalculator : ICalculator      { public int Execute(int x, int y)          { return x - y;          }      }

在主函数中进行调用:

Code 12
 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
[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
 
 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
 public class User          {              [Import("Role")]public String Role { get; set; }          }

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

Code 16
 
public classDatabaseProvider { [Export("Role")] public String AvailableRole { get { return"Developer"; } } }

在主调用程序的目录下,我们创建一个Extensions的目录,然后把相关的扩展组件都放在该目录下,并在主调用程序中,为DirectoryWatchingComponentCatalog实例加入Extensions目录,这样就避免了与具体的扩展应用程序产生依赖,如下代码所示:

Code 17
  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的一些使用,希望对大家有所帮助。

转载于:https://www.cnblogs.com/tuyile006/archive/2011/06/02/2070092.html

使用MEF方便的扩展相关推荐

  1. 使用MEF构建可扩展的Silverlight应用

    "托管扩展性框架(Managed Extensibility Framework,简称MEF),是微软 .NET框架下为提高应用和组件复用程度而推出的,用于使组件能够最大化的重用 .使用ME ...

  2. MEF(可扩展框架)使用总结

    一般情况下,我们对系统要求: 1.对扩展开发对修改关闭 2.高层模块不应该依赖于低层模块,应该依赖于抽象 实际上,这是遵循了面向对象的设计原则中的开放封闭原则和依赖倒置原则,其所做的事情就是为了提高系 ...

  3. .NET MEF托管可扩展框架

    MEF简介: 今天学习了下MEF框架,MEF,全称Managed Extensibility Framework(托管可扩展框架).MEF是专门致力于解决扩展性问题的框架,MSDN中对MEF有这样一段 ...

  4. MEF程序设计指南七:使用目录(Catalog)动态装载xap与目录筛选(Filtered Catalog)...

    如果不使用MEF进行托管扩展处理,只有通过WebClient进行程序包的下载.解析.实际上MEF的动态下载的底层实现一样是使用的WebClient,然后利用AggregateCatalog进行动态组合 ...

  5. MEF实现设计上的“松耦合”(一)

    1.什么是MEF 先来看msdn上面的解释:MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展, ...

  6. MEF程序设计指南(转)

    在MEF之前,人们已经提出了许多依赖注入框架来解决应用的扩展性问题,比如OSGI 实现以Spring 等等.在 Microsoft 的平台上,.NET Framework 自身内部包含组件模型和 Sy ...

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

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

  8. C# 依赖注入 MEF

    1.什么是MEF 先来看msdn上面的解释:MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展, ...

  9. 【C#进阶系列】【MEF框架(一)】

    C#进阶系列 第一章 [C#进阶系列][MEF框架(一)] 文章目录 C#进阶系列 前言 一.MEF介绍 二.为什么要用MEF 三.MEF的概念 四.使用示例 五.MEF框架的好处 六.源码链接 总结 ...

最新文章

  1. MapReduce的数据去重功能
  2. 初探云原生应用管理(二): 为什么你必须尽快转向 Helm v3
  3. All in会员经济的知乎,能否实现商业化大跃进?
  4. Android和IOS 调用 支付宝和微信 支付方法
  5. Codeforces Round #470 (rated, Div. 2, based on VK Cup 2018 Round 1)B. Primal Sport
  6. Python读写txt
  7. RFC 8998: ShangMi (SM) Cipher Suites for TLS 1.3
  8. 修改驱动器重定向显示格式
  9. Ubuntu 11.04 下安装配置 JDK 7
  10. Atitit 命令行执行sql 跨语言 目录 1.1. 无需输入密码,那就不要-p参数即可 1 1.2. 4.使用mysql命令执行 1 1.3. 5.mysql命令执行sql,并将查询结果保存到
  11. 面试 之 git工作流
  12. 什么是 JxBrowser
  13. MATLAB 官方文档
  14. 从零开始用uniapp搭建一个APP
  15. mysql 汉字笔画排序规则_SQL Server 与 MySQL 中排序规则与字符集相关知识的一点总结...
  16. 年货节买蓝牙耳机哪个品牌最好?数码达人力荐的几大机型!
  17. 计算机图形学原理及实践学习笔记第一章
  18. idea如何选择性合并其他分支的代码
  19. 文件上传漏洞靶场upload-labs学习(pass11-pass15)
  20. Blender 制作一个简单的圆形

热门文章

  1. 讯飞C/C++语音合成基础篇
  2. java calendar 转换_[java]转:String Date Calendar之间的转换
  3. pc显示器分辨率 前端_2020电竞显示器推荐
  4. 拼装机器人感想_智能机器人心得体会
  5. 计算机网络之数据链路层:15、以太网、适配器、MAC地址
  6. 1-4:学习shell之操作文件与目录
  7. vs下使用qt设置应用程序的图标
  8. Ubuntu apt update(apt-get update)报错、失败
  9. C/C++函数指针与回调函数总结(函数指针数组)
  10. Qt:Qt实现飞秋拦截助手—ARP攻击