最近在寫一篇關于如何擴展 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。
Import
導入,這里建議作為一個名詞來理解,即一個接受者,它可以接受外來的東東。就好比是下圖中的盒子,它可以接受其它積木。
十三孔智力盒
Export
導出,同樣建議以一個名詞來理解,即一個第三方的產物。它就像上圖中不同顏色的積木,這些積木不屬于這個盒子,但是能被放入盒子中,來豐富盒子的功能。
積木
Contract
協議。要想使盒子能接受積木(比如,圓柱體只能放入圓形的接口中),那這些積木必須符合一定的形狀。而這些形狀就相當于是應用程序和第三方擴展之間的一個協議。
Compose
組合(動詞),即將多個符合協議要求的部件組合在一起,構成一個功能豐富的應用程序。就好比是將不同形狀的積木,按照接口的形狀組合在一起。
MEF 會動態查找用戶所指定的目錄,如果發現該目錄中的程序集滿足協議要求,就會啟動自身的組合引擎,然后根據不同的協議約定把這些擴展導入到應用程序內部。
對幾個關鍵的概念清楚了之后,我們就可以開始實踐了。最終的效果是窗體上會動態加載某一目錄下的dll,并自動為每個新功能添加一個按鈕,當點擊按鈕就會執行新的功能。
最終效果
首先,定義一個協議。
這個和普通定義接口沒什么兩樣。
1 public interface iplugin2 {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 try13 {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 擴展應用程序》
|
新聞熱點
疑難解答