.NET框架之---MEF託管可擴充套件框架
MEF簡介:
今天學習了下MEF框架,MEF,全稱Managed Extensibility Framework(託管可擴充套件框架)。MEF是專門致力於解決擴充套件性問題的框架,MSDN中對MEF有這樣一段說明:
Managed Extensibility Framework 或 MEF 是一個用於建立可擴充套件的輕型應用程式的庫。 應用程式開發人員可利用該庫發現並使用擴充套件,而無需進行配置。 擴充套件開發人員還可以利用該庫輕鬆地封裝程式碼,避免生成脆弱的硬依賴項。 通過 MEF,不僅可以在應用程式內重用擴充套件,還可以在應用程式之間重用擴充套件。
我們通過例子1來看下MEF是如何工作的:
例子1:
新建個WPF程式--MEFtestpro,新增引用System.ComponentModel.Composition,MEF的核心就是在此類庫中實現的
專案結構圖:
新增一個介面IApple.cs
namespace MEFtestpro
{
public interface IApple
{
string GetAppleColor();
}
}
然後新增三個類RedApple.cs
namespace MEFtestpro { [Export ("Apple",typeof(IApple))] //將RedApple類匯出型別為IApple介面 class RedApple : IApple { public string GetAppleColor() { return "Red"; } } [Export("Apple", typeof(IApple))] //將GreedApple類匯出型別為IApple介面 class GreedApple : IApple { public string GetAppleColor() { return "Green"; } } [Export("Apple", typeof(IApple))] //將YellowApple類匯出型別為IApple介面 class YellowApple : IApple { public string GetAppleColor() { return "Yellow"; } } }
最後,主程式MainWindow.xaml.cs
namespace MEFtestpro { public partial class MainWindow : Window { [ImportMany("Apple")] //Apple是契約名字,可以任意起,但是要注意別重名 public IEnumerable<IApple> Apples { get; set; } public MainWindow() { InitializeComponent(); this.Compose(); if (this.Apples != null) { string s=string.Empty; foreach (var apple in Apples) //將內容顯示在label上 { s=s+ apple.GetAppleColor()+"\r\n"; label.Content = s; } } } //這個方法表示添加當前Program這個類到組合容器,為什麼要新增到組合容器? //是因為只要新增到組合容器中之後,如果該類裡面有Import,MEF才會自動去尋找對應的Export。 //這也就是為什麼使用MEF前必須要組合部件的原因。 private void Compose() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); CompositionContainer container = new CompositionContainer(catalog); container.ComposeParts(this); } } }
然後執行看結果,如下:
可以看到,我們沒有例項化類,而是僅僅通過Export和Import一箇中間型別(IApple),就實現了呼叫類中的方法!
這就實現了主程式和類之間的解耦,大大提高了程式碼的擴充套件性和易維護性!
可能有人就會說多此一舉,既然我們可以例項化類,為什麼非要用這種奇怪的語法。
其實如果我們站在軟體框架設計的層面,它的好處就是可以減少dll之間的引用,使你的程式更加健壯可擴充套件
接下來請看例子2.
例子2:
新建控制檯程式MEFtestPro2
專案結構圖:
新增.NET類庫Fruit,裡面包含了一個介面IFruit
namespace Fruit
{
public interface IFruit
{
string GetFruitName();
}
}
新增.NET類庫Banana,引用Fruit.DLL
namespace Banana
{
[Export(typeof(IFruit))]
public class Banana : IFruit
{
public string GetFruitName()
{
return "Banana";
}
}
}
新增.NET類庫Orange,引用Fruit.DLL
namespace Orange
{
[Export(typeof(IFruit))]
public class Orange : IFruit
{
public string GetFruitName()
{
return "Orange";
}
}
}
最後主程式program.cs,引用Fruit.DLL
namespace MEFtestPro2
{
class Program
{
[ImportMany(typeof(IFruit))]
public IEnumerable<IFruit> fruits { get; set; }
static void Main(string[] args)
{
Program pro = new Program();
pro.Compose();
foreach (var f in pro.fruits) //列印輸出
{
Console.WriteLine(f.GetFruitName());
}
Console.Read();
}
private void Compose()
{
var catalog = new DirectoryCatalog("fruits"); //fruits是一個目錄名稱,就是主程式所在目錄(bin-Debug-fruits)資料夾(我們需要提前建立好)
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
}
現在,我們把生成的Banana.dll和Orange.dll拷貝到這個資料夾下,如圖:
然後執行才可以正確輸出資訊(畢竟我們沒有引用那個專案),如圖:
注意,我們僅僅是把Banana.dll和Orange.dll拷貝到我們指定的目錄,然後通過MEF匯入匯出中間型別(IFruit),
實現了主程式呼叫未知的DLL中的方法,而主程式並未引用該DLL
總結一下MEF框架的好處:
1.解耦。試想下,如果主程式引用了Banana.dll和Orange.dll,那麼就意味著你可以無限制的開放DLL中類,屬性,方法的訪問許可權,也就意味著主程式中會出現很多耦合的程式碼,哪天你想移除這個DLL,程式肯定編譯失敗,而且你要手動刪除這些耦合程式碼,而MEF因為是通過中間介面來完成呼叫的,所以只向外暴露了接口裡面的成員,程式設計師是無法任意呼叫DLL中的任何方法,只能通過介面來呼叫。就算刪掉這個DLL,程式也能正常執行!
2.可擴充套件性。舉個例子,假設你的程式已經移交給客戶了,哪天客戶說我不想看Banana了,我想換一個水果,蘋果Apple,這時,你只需重寫一個Apple.DLL,使其繼承並實現IFruit介面,然後,只要將Apple.dll交給客戶,並讓其覆蓋Banana.DLL,開啟程式,你會發現香蕉變成了蘋果。是不是很方便!如果是以前,你可能得重新將所有有關banana的東西全部替換,然後重新編譯,釋出,再將整個程式移交客戶,這樣說大家應該都明白了!
3.MEF不僅可以匯出類,還可以匯出方法,屬性,不管是私有還是公有,從而滿足更多的需求!
參考資料:http://www.cnblogs.com/yk123/p/5350133.html
未完待續。。。。。