天天看點

學習MEF系列(2):導入(Import)和導出(Export)

前言:

MEF不同于其他IOC容器(如:Castle)很重要的原因在于它使用了特性化程式設計模型,何為特性化程式設計這裡不細究,簡單說明下兩個概念:“特性”和“程式設計模型”:

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

  程式設計模型(Programming Model):MEF中的程式設計模型是定義 MEF 所操作的概念性對象集的特定方法。MEF預設使用特性化程式設計模型,但是使用者也可自定義程式設計模型。

  導入(Import),導出(Export)是MEF擴充性機制實作的基礎,是非常重要的兩種部件。MEF中導入、導出部件均是通過特性來确定的(如:标記有[Export]特性的我們稱之為導出部件)。本文簡單的介紹下MEF中得導入和導出。

導入和導出基礎:

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

public interface ILog
{
     void Log(Exception ex);
}

//導出的類型為ILog[Export(typeof(ILog))]
pulic class FileLog:ILog
{
     public void Log(Exception ex)
     {
     }
}

pulic class MyClass
{
        //導入的類型預設為ILog,可以與導出比對    [Import]
    pulic Ilog MyLog
    {
        get;
        set;
    }
}
           

導入的類型:

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

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

public class MyClass
{
    [Import(“MyLog”)]
    public dynamic MyLog{ get; set; }
}
           

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

public class MyClass
{
    [Import]
    public Lazy<ILog> MyLog { get; set; }
}
           

必備導入:在實際工作中我們經常會用到依賴注入,通過構造函數将我對象注入到本類中是依賴注入的一種形式,MEF也可以完成構造注入。

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

public class MyClass 
{
    private ILog _myLog;

    public MyClass() { }

    [ImportingConstructor] 
    public MyClass(ILog myLog) 
    {
        _myLog = myLog;
    }
}
           

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

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

public class MyClass
{
     [ImportMany]
     public IEnumerable<ILog> MyLogs { get; set; }
}
           

導入和導出的繼承

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

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

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

本文參考:http://msdn.microsoft.com/zh-cn/library/ee155691.aspx#MtViewDropDownText