天天看點

MEF 導入(Import)和導出(Export)

前言:

MEF不同于其他IOC容器(如:Castle)很重要的原因在于它使用了特性化程式設計模型(涉及到兩個概念:“特性”和“程式設計模型”)。

特性(Attribute):舉例來說就是我們在開發過程中在類上标記的如:[Serializable]的标簽。

程式設計模型(Programming Model):MEF中的程式設計模型是定義 MEF 所操作的概念性對象集的特定方法。MEF預設使用特性化程式設計模型,但是使用者也可自定義程式設計模型。MEF中導入、導出間的比對均是通過特性來實作的。本文簡單的介紹下MEF中得導入和導出。

導入和導出基礎:

在上一篇文章中我們說過導出提供服務,而導入是使用服務。導入使用 Import特性聲明 ,導出使用 Export 特性聲明。 Export 特性可修飾類、字段、屬性或方法,而 Import 特性可修飾字段、屬性或構造函數參數。導入和導出的比對必須要有相同的Contract,Contract有兩部分組成:ContractName(名稱)和ContractType(類型),隻有名稱和類型都完全相同,才會認為導出能夠滿足特定導入。如:

View Code  1 public interface ILog 2 { 3      void Log(Exception ex); 4 } 5 6 //導出的類型為ILog[Export(typeof(ILog))] 7 pulic class FileLog:ILog 8 { 9      public void Log(Exception ex) 10      { 11      } 12 } 13 14 pulic class MyClass 15 { 16         //導入的類型預設為ILog,可以與導出比對    [Import] 17     pulic Ilog MyLog 18     { 19         get; 20         set; 21     } 22 }

導入的類型:

MEF中導入的類型包括了:動态導入、延遲導入、必備導入和可選導入。

動态導入:使用dynamic關鍵字進行導入,協定類型從 dynamic 關鍵字推斷而出,則它将與任何協定類型比對。是以在使用倒台導入時必須指定協定名稱,否則将未比對任何導出

1 public class MyClass 2 { 3     [Import(“MyLog”)] 4     public dynamic MyLog{ get; set; } 5 }

延遲導入:我們知道延遲加載,那麼延遲導入同延遲加載的作用一樣:導入和導出比對時不會立即執行個體化對象,延遲導入需要使用Lazy<T>來聲明導入:

1 public class MyClass 2 { 3     [Import] 4     public Lazy<ILog> MyLog { get; set; } 5 }

必備導入:在我們的日常工作中我們可能經常會用到依賴注入,依賴注入有一種方式便是通過構造函數将我們需要的對象注入到本類中,MEF也可以完成相同的工作。

    導出的 MEF 部件通常由組合引擎建立,預設情況下,在建立部件時,組合引擎将使用無參數的構造函數。要想使用自定義構造函數需要使用特性:ImportingConstructor。使用必備導入時必須同時提供預設構造和ImportingConstructor的構造方法,否則将出錯.MEF允許導入和導出的循環依賴。

 1 public class MyClass 2 { 3     private ILog _myLog; 4 5     public MyClass() { } 6 7     [ImportingConstructor] 8     public MyClass(ILog myLog) 9     { 10         _myLog = myLog; 11     } 12 }

可選導入:在MEF中如果導入得不到比對将會組合失敗,但我們需要容錯時,使用AllowDefault 屬性指定導入為可選:[Import(AllowDefault = true)]。這樣即使導入沒有得到比對也不會影響組合容器對部件的組合。

導入多個對象:導入和導出可以支援一對多的關系,使用ImportMany特性可以導入多個服務(導出),使用ImportMany标記的導入始終是可選導入。

1 public class MyClass 2 { 3     [ImportMany] 4     public IEnumerable<ILog> MyLogs { get; set; } 5 }

導入和導出的繼承

導入的繼承:導入始終由子類繼承,子類擁有和父類相同的導入。

導出的繼承:使用Export特性的導出部件始終不能呗繼承,如果想要導出部件可以被繼承需要使用關鍵字:InheritedExport,子類将提供與父類相同的導出(包括ContractName和ContractType)。但是InheritedExport隻能标記在類上,也就是說成員導出永遠不能被繼承。

後記:導入和導出相關的概念還包括中繼資料,以及自定義導出相關知識,将在下一篇中詳細介紹。

作者:ps_zw

繼續閱讀