上一篇學習完了MEF的基礎知識,編寫了一個簡單的DEMO,接下來接著上篇的內容繼續學習,如果沒有看過上一篇的內容,
請閱讀:http://www.cnblogs.com/yunfeifei/p/3922668.html。
下面我們來主要講解一下MEF中的匯入和匯出,還是上一篇的程式碼(這篇中,我還會貼出完整的程式碼),修改Program的程式碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; namespace MEFDemo { class Program { [Import("MusicBook")] public IBookService Service { get; set; } static void Main(string[] args) { Program pro = new Program(); pro.Compose(); if (pro.Service != null) { Console.WriteLine(pro.Service.GetBookName()); } Console.Read(); } private void Compose() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); CompositionContainer container = new CompositionContainer(catalog); container.ComposeParts(this); } } }
修改MusicBook的程式碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.Composition; namespace MEFDemo { [Export("MusicBook",typeof(IBookService))] public class MusicBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "MusicBook"; } } }
注意,標紅的是改動過的地方,其他地方的程式碼沒有變,上一次我們使用的是Export的方法是[Export(typeof(IBookService))],這次前面多了一個引數,沒錯,這個就是一個契約名,名字可以隨便起,而且可以重複,但是如果名字亂起,和其他DLL中的重複,到時候會導致程式出現很多Bug,最好按照一定的規範去起名字。
這裡有了契約名以後,匯入(Import)時就要指定的契約名,否則將無法找到MusicBook,Export還有一個方法是[Export("Name")],這個方法只指定了契約名,沒有指定匯出型別,那麼預設的匯出型別是object型別,在匯入時匯出到的物件就要為object型別,否則將匹配不到那個元件。
到現在,我們只寫了一個介面和一個實現類,匯出的也是一個類,下面我們多新增幾個類來看看會怎麼樣,為了方便大家測試,我把實現介面的類寫在一個檔案裡面,新加幾個類後,的MusicBook類檔案程式碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.Composition; namespace MEFDemo { [Export("MusicBook",typeof(IBookService))] public class MusicBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "MusicBook"; } } [Export("MusicBook", typeof(IBookService))] public class MathBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "MathBook"; } } [Export("MusicBook", typeof(IBookService))] public class HistoryBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "HistoryBook"; } } }
這裡新增兩個類,HistoryBook和MathBook,都繼承自IBookService介面,注意他們的契約名都相同,都為MusicBook,後面再詳細的說這個問題,修改後的program的程式碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; namespace MEFDemo { class Program { [ImportMany("MusicBook")] public IEnumerable<IBookService> Services { get; set; } static void Main(string[] args) { Program pro = new Program(); pro.Compose(); if (pro.Services != null) { foreach (var s in pro.Services) { Console.WriteLine(s.GetBookName()); } } Console.Read(); } private void Compose() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); CompositionContainer container = new CompositionContainer(catalog); container.ComposeParts(this); } } }
這裡需要注意的是標紅的兩行程式碼,[ImportMany("MusicBook")]還有下面的宣告變成了IEnumerable<>,因為要匯出多個例項,所以要用到集合,下面採用foreach遍歷輸出,執行的結果如下圖:
一共三個,都輸出了,對吧!是不是很好用啊,哈哈~~
當然,如果想全部輸出,可以向第一篇文章中那樣,匯入和匯出時都不寫契約名,就會全部匯出。那麼寫契約名有什麼好處呢?
下面我們用程式碼說明問題,修改實現類的契約名如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.Composition; namespace MEFDemo { [Export("MusicBook",typeof(IBookService))] public class MusicBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "MusicBook"; } } [Export("MathBook", typeof(IBookService))] public class MathBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "MathBook"; } } [Export("HistoryBook", typeof(IBookService))] public class HistoryBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "HistoryBook"; } } }
現在三個類的契約名都不相同了,其他的程式碼不動,再次執行程式看看,是不是現在只輸出MusicBook了,同理,修改[Import("Name")]中的契約名稱,就會匯入指定含有名稱的類,契約名可以重複,這一以來,我們就可以用契約名給類進行分類,匯入時可以根據契約名來匯入。
注意:IEnumerable<T>中的型別必須和類的匯出型別匹配,如類上面標註的是[Exprot(typeof(object))],那麼就必須宣告為IEnumerable<object>才能匹配到匯出的類。
例如:我們在類上面標註[Export("Book")],我們僅僅指定了契約名,而沒有指定型別,那麼預設為object,此時還用IEnumerable<IBookService>就匹配不到。
那麼,這種情況就要在輸出是進行強制型別轉換,程式碼如下:
[Export("MusicBook")] public class MusicBook : IBookService { public string BookName { get; set; } public string GetBookName() { return "MusicBook"; } }
program中的程式碼改變如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; namespace MEFDemo { class Program { [ImportMany("MusicBook")] public IEnumerable<object> Services { get; set; } static void Main(string[] args) { Program pro = new Program(); pro.Compose(); if (pro.Services != null) { foreach (var s in pro.Services) { var ss = (IBookService)s; Console.WriteLine(ss.GetBookName()); } } Console.Read(); } private void Compose() { var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly()); CompositionContainer container = new CompositionContainer(catalog); container.ComposeParts(this); } } }
這樣就可以正常執行了~~
MEF系列文章:
C#可擴充套件程式設計之MEF學習筆記(一):MEF簡介及簡單的Demo
C#可擴充套件程式設計之MEF學習筆記(二):MEF的匯出(Export)和匯入(Import)
C#可擴充套件程式設計之MEF學習筆記(三):匯出類的方法和屬性
C#可擴充套件程式設計之MEF學習筆記(四):見證奇蹟的時刻
C#可擴充套件程式設計之MEF學習筆記(五):MEF高階進階