1. 程式人生 > >.NET框架之---MEF託管可擴充套件框架

.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

未完待續。。。。。