最近在写一篇关于如何扩展 Visual Studio 编辑器的文章时,用到了 MEF,所以打算写一篇文章提一下这个技术点。本篇文章并不打算详细介绍 MEF,只是一个最简单的入门,相信您在阅读本篇文章后,能够迅速开发出一个可扩展的应用程序。服务器
MEF(Managed Extensibility Framework),是微软推出的一款用于搭建可扩展应用程序的框架,起初是独立于 .Net 发布的,后来集成到了 .Net 4.0 中。使用该框架能够很是轻松地扩展一个已发布的应用程序的功能,连 Visual Studio IDE 中的代码编辑器窗口也采用了MEF的思想,所以大大方便了开发人员对编辑器的扩展。框架
MEF 可用在任何使用 .NET Framework 的地方。能够在客户端应用程序中使用 MEF(不管应用程序使用的是 Windows 窗体、WPF,仍是任何其余技术),也能够在使用 ASP.NET 的服务器应用程序中使用 MEF。编辑器
Importpost
导入,这里建议做为一个名词来理解,即一个接受者,它能够接受外来的东东。就比如是下图中的盒子,它能够接受其它积木。this
十三孔智力盒编码
Exportspa
导出,一样建议以一个名词来理解,即一个第三方的产物。它就像上图中不一样颜色的积木,这些积木不属于这个盒子,可是能被放入盒子中,来丰富盒子的功能。设计
积木3d
Contractcode
协议。要想使盒子能接受积木(好比,圆柱体只能放入圆形的接口中),那这些积木必须符合必定的形状。而这些形状就至关因而应用程序和第三方扩展之间的一个协议。
Compose
组合(动词),即将多个符合协议要求的部件组合在一块儿,构成一个功能丰富的应用程序。就比如是将不一样形状的积木,按照接口的形状组合在一块儿。
MEF 会动态查找用户所指定的目录,若是发现该目录中的程序集知足协议要求,就会启动自身的组合引擎,而后根据不一样的协议约定把这些扩展导入到应用程序内部。
对几个关键的概念清楚了以后,咱们就能够开始实践了。最终的效果是窗体上会动态加载某一目录下的dll,并自动为每一个新功能添加一个按钮,当点击按钮就会执行新的功能。
最终效果
首先,定义一个协议。
这个和普通定义接口没什么两样。
1 public interface IPlugin 2 { 3 string Text { get; } 4 5 void Do(); 6 }
安装接受者
有了协议以后,就须要给应用程序安一个接受者。让这个应用程序能够经过接受者来获取第三方扩展。MEF 提供了[Import] 和 [ImportMany] 两种 attribute。 区别就是 Import 只能接受符合协议的一个扩展,而 ImportMany 能够接受多个,并把多个扩展放入集合中。
1 public partial class Form1 : Form 2 { 3 public Form1() 4 { 5 InitializeComponent(); 6 } 7 8 [ImportMany] 9 public IEnumerable<IPlugin> plugins; 10 11 private void Form1_Load(object sender, EventArgs e) 12 { 13 } 14 15 }
提供一个符合协议的产物
这个产物的生产过程其实就是实现接口的过程,惟一的区别是咱们要为这个实现打上个标签,从而告诉咱们的组合引擎这个东西是给接受者的。MEF 提供了 Export 来暗示这是一个能够提供给接受者的产物。
1 [Export(typeof(IPlugin))] 2 public class MyPlugin:IPlugin 3 { 4 public string Text 5 { 6 get 7 { 8 return "This is a demo"; 9 } 10 } 11 12 public void Do() 13 { 14 MessageBox.Show(Text); 15 } 16 }
发动引擎
万事俱备,就差发动了。前面说了引擎的主要做用就是把发现扩展,同时把这些扩展组合到应用程序中。
1 private CompositionContainer _container; 2 private void Init() 3 { 4 try 5 { 6 MyPlugin my = new MyPlugin(); 7 this._container.ComposeParts(this, my);//把扩展和实例组合在一块儿 8 } 9 catch (CompositionException compositionException) 10 { 11 Console.WriteLine(compositionException.ToString()); 12 } 13 }
上面的代码虽然实现了组合的功能,可是却硬把产物给编码进去了。要是每次开发了新的扩展,都得这样修改应用程序代码,那就彻底没有使用MEF的必要了,并且也违反了开放封闭的设计原则。
把上面的代码改一改。
1 private CompositionContainer _container; 2 private void Init() 3 { 4 //设置目录,让引擎能自动去发现新的扩展 5 var catalog = new AggregateCatalog(); 6 catalog.Catalogs.Add(new DirectoryCatalog("D:\\plugin\\")); 7 8 //建立一个容器,至关因而生产车间 9 _container = new CompositionContainer(catalog); 10 11 //调用车间的ComposeParts把各个部件组合到一块儿 12 try 13 { 14 this._container.ComposeParts(this);//这里只须要传入当前应用程序实例就能够了,其它部分会自动发现并组装 15 } 16 catch (CompositionException compositionException) 17 { 18 Console.WriteLine(compositionException.ToString()); 19 } 20 }
上面的代码会自动去发现扩展,而后加入到应用程序中来。你要作的只是把新扩展的程序集放入 D:\\plugin 目录中就能够了。是否是很方便呢?
Managed Extensibility Framework (MEF)
本文来源于 《如何用 MEF 扩展应用程序》