MEF,是微軟.net框架下的一個框架類庫。可以使你的程序低耦合的加載擴展。在開發插件,或者開發一些需要靈活擴展的功能的時候經常用到。例如微軟給出的計算器的例子。當你開發計算器的時候,初始功能只提供了加減功能。但后來你要擴展乘法,除法功能。顯然,如果去改整個程序就會使問題變得麻煩,并且有不可預知的問題。所以微軟提供給我們使用MEF來通過動態加載擴展的方法來給程序增加新功能。另外,mef,也可以用來實現依賴注入,控制反轉。
我們先從最簡單的DEMO開始學習mef.
using System;using System.Collections.Generic;using System.ComponentModel.Composition;using System.ComponentModel.Composition.Hosting;using System.Reflection;namespace MEFDEMO{ class PRogram { [Import] public string Message { get; set; } static void Main(string[] args) { Program program = new Program(); program.Run(); } public void Run() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this); Console.WriteLine(Message); Console.ReadKey(); } } public class SimpleHello { [Export] public string Message { get { return "HelloWorld!"; } } }}這是一個最簡單的例子。從上面可以看出一個簡單的mef實現由下面幾個部分組成
1. 一個程序用來調用的入口 [Import] public string Message { get; set; }
2. 方法的具體實現 [Export] public string Message{get { return "HelloWorld!"; }}
方法的具體實現也就是我們可以動態增加的部分。和一般的接口實現相比,通過MEF的實現使其更靈活,更易擴展。可動態添加
3. 將上面兩個方法組合起來的,建立兩者之間的聯系。
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
關于如何建立兩者之間的聯系,在這個例子中我們是通過,獲得當前程序集運行的目錄,將當前目錄放到一個容器中,最后通過ComposeParts(this);方法將容器container中export的方法import到實現了import特性的具體實現。我們現在來了解幾個MEF中常用到的類。
ComposablePart 類:定義用于導入對象和生成已導出對象的可組合部件的抽象基類。也就是說這個類的每一個實例里面都放了里面放了一組ExportDefinitions和ImportDefinitions,我們可以把每一個實例稱作一個部件。
ComposablePartCatalog 類:表示收集并返回ComposablePartDefinition對象的可組合部件目錄的抽象基類。也就是里面存放了一堆部件所在程序集的目錄,注意這里不是存放了一堆部件,而是這些部件所在程序集的目錄,也就是我們去找所有部件的索引項。
ExportProvider 類:檢索與指定的ImportDefinition對象相匹配的導出。這個類的作用很明確,就是用來尋找與ImportDefinition對象匹配的ExportDefinition
CompositionContainer 類:管理部件的組合。也就是用來管理ComposablePart部件的一個容器類。里面放了我們的一組組部件。注意這個類繼承自ExportProvider這個類。
上面幾個類是mef中抽象出來的幾個類,理清這幾個類的關系,我們在應用mef的時候才能高清mef的使用步驟。
下面這幾個類繼承自ExportProvider 類,都能訪問到相關的部件,但每一個類的側重都不同。
System.ComponentModel.Composition.Hosting.AggregateExportProvider:
檢索由ExportProvider對象的集合提供的導出。System.ComponentModel.Composition.Hosting.CatalogExportProvider:
從目錄中檢索導出。 System.ComponentModel.Composition.Hosting.ComposablePartExportProvider:
檢索來自某個部件的導出。System.ComponentModel.Composition.Hosting.CompositionContainer:
側重于管理部件,上面定義已給出。
下面這幾個類繼承自 ComposablePartCatalog類,都是每個部件的存放目錄,但每一個類的側重都不同。
System.ComponentModel.Composition.Hosting.AggregateCatalog:
合并ComposablePartCatalog對象元素的目錄。System.ComponentModel.Composition.Hosting.AssemblyCatalog:
在托管代碼程序集中發現特性化部件。System.ComponentModel.Composition.Hosting.DirectoryCatalog:
發現所指定目錄中的程序集的特性化的部分。System.ComponentModel.Composition.Hosting.TypeCatalog:
從類型集合發現特性化部件。
其它一些類:
CompositionBatch 類:表示一組將添加至一個事務性組合的容器中或從容器中移除的ComposablePart對象。
ExportAttribute 類:指定某個類型、屬性、字段或方法提供特定的導出。
ImportAttribute 類:指定屬性、字段或參數值應由CompositionContainer提供。
總之,常用到的類有以上幾個,還有一些其它用到的,請直接去參考msdn.
理解了上述幾個類,然后我們去看我們上面的例子中將部件組合的過程。
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
取到當前程序集運行的目錄,這兒當然我們也可以去取別的程序集的目錄,比如我們插件所在的擴展目錄。可用如下代碼去取
System.ComponentModel.Composition.Hosting.AggregateCatalog category = new System.ComponentModel.Composition.Hosting.AggregateCatalog(); foreach (var file in System.IO.Directory.GetFiles(@"C:/Users/wfm/Documents/Visual Studio 2013/Projects/WPFTest/TestReference/bin/Debug")) { if (file.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase)) { try { var assembly = Assembly.LoadFile(file); if (assembly == Assembly.GetCallingAssembly()) continue; category.Catalogs.Add(new System.ComponentModel.Composition.Hosting.AssemblyCatalog(assembly)); } catch { } } } Container = new CompositionContainer(category, true); this.Container.ComposeParts(this);
var container = new CompositionContainer(catalog);
這句代碼創建了一個容器,創建容器很簡單,這要傳入一個ComposablePartCatalog類或者其子類就可以,也可以傳入ExportProvider類,具體的看該方法的重載。
container.ComposeParts(this);
這里ComposeParts是一個擴展方法。調用的時候省略第一個參數。所以這里傳入的this,類型:System.Object[]要組合的特性化對象的數組。也就是把這兒的[Import] public string Message { get; set; } 傳過去,然后容器就去尋找和該需要的導入對象匹配的導出對象。
在這個例子中我們是用的container.ComposeParts(this);來組合的導入導出。但是還有其他方法。例如: container.SatisfyImportsOnce(this); container.Compose(batch); T 實例= Container.GetExportedValue<T>();然后通過實例去調用。
本文地址:http://m.survivalescaperooms.com/santian/p/4355730.html
博客地址:http://m.survivalescaperooms.com/santian/
轉載請以超鏈接形式標明文章原始出處。新聞熱點
疑難解答