1. 程式人生 > >MEF學習總結(4)---Container層

MEF學習總結(4)---Container層

ret nba enum https ive src lib nco 註入

通過AttributeedModelPrograming,我們可以聲明暴露組件,依賴組件,發現組件,但是所有這些需要有一個觸發點。即需要把所有這些組合在一起來協同工作,最終實現依賴註入。這就是Container層所做的事情.

CompositionContainer            

CompositionContainer在MEF中負責組合其他元素來實現依賴註入。看看他的一個構造函數:

public CompositionContainer(
    ComposablePartCatalog catalog,//指明如何發現組件
    bool isThreadSafe,//指明是否需要線程安全,這個如果在多線程模型下需要設為true
    
params ExportProvider[] providers )

可以看出,我們把Catalog傳入container,即告訴了container如何去發現組件,再結合通過Export/Import各種attributes定義好的依賴模型。不難理解container已經可以去根據依賴模型註入依賴了。接下來就是觸發點。Container提供了一系列API來填充給定組件中的依賴。主要是如下幾個:

技術分享 Compose(CompositionBatch)

Adds or removes the parts in the specified CompositionBatch from the container and executes composition.

技術分享 GetExportedValue<T>()

Returns the exported object with the contract name derived from the specified type parameter. If there is not exactly one matching exported object, an exception is thrown.(Inherited fromExportProvider.)

技術分享 GetExportedValue<T>(String)

Returns the exported object with the specified contract name. If there is not exactly one matching exported object, an exception is thrown.(Inherited from ExportProvider.)

技術分享 SatisfyImportsOnce(ComposablePart)

Satisfies the imports of the specified ComposablePart object without registering it for recomposition.(當前組件不會被註冊為Export組件)

然後在AttributedModelService中提供了一系列面向組件實例的API,常用的Extension方法有如下幾個:

技術分享技術分享 ComposeParts(CompositionContainer, Object[])

Creates composable parts from an array of attributed objects and composes them in the specified composition container.

技術分享技術分享 CreatePart(Object)

Creates a composable part from the specified attributed object.

技術分享技術分享 SatisfyImportsOnce(ICompositionService, Object)

Composes the specified part by using the specified composition service, with recomposition disabled.

ExportProvider          

其實到這裏似乎可以認為,Container負責了實際組件對象的創建。因為Catalog只定義了組件的發現,然後生成PartDefinition。但其實真實情況不是這樣,Container其實這是個接口層,真正負責組件實例的創建是由第一篇中的那幅圖中還沒有用過的ExportProvider來負責。看看ExportProvider的接口定義:

技術分享

看上去有很多方法,其實都是在做一件事,根據ImportDefinition來得到一個Export對象(組件實例的包裝)

技術分享

內置的ExportProvider有如下幾種:

CompositionContainer - CompositionContainer自身其實也是一種ExportProvider

MutableExportProvider - 當創建CompositionContainer時,Container內部會創建該ExportProvider,然後負責管理通過調用Container接口手動添加的組件

ComposablePartCatalogExportProvider - 它負責管理通過PartCatalog發現的組件,當創建CompositionContainer的時候如果傳入了Catalog,Container會創建該ExportProvider.

AggregatingExportProvider - 根據名字即可知道,該ExportProvider是用來組合其他ExportProvider的,上述創建CompositionContainer的時候創建的ExportProvider最後都會聚合在該Provier中統一管理。

也可以自定義ExportProvider,然後創建CompositionContainer的時候加入到Container中,則可以對MEF進行擴展。

Recomposition            

在依賴的組件已經註入之後,如果後續對Export的組件進行添加和刪除後,想要更新原來已經註入的依賴組件。則可以使用Recomposition。看如下代碼:

public interface ILog
    {

    }

    [Export(typeof(ILog))]
    [ExportMetadata("Type", "file")]
    public class FileLog : ILog
    {

    }

    [Export(typeof(ILog))]
    [ExportMetadata("Type", "db")]
    public class DBLog : ILog
    {

    }

    public class TaskExecutor
    {
        [ImportMany(typeof(ILog), AllowRecomposition = true)]
        public IEnumerable<ILog> _loggers;
    }

    class Program
    {

        static void Main(string[] args)
        {

            var container = new CompositionContainer(new TypeCatalog(typeof(DBLog)));

            var taskExecutor = new TaskExecutor();
            container.ComposeParts(taskExecutor);

            Console.WriteLine(taskExecutor._loggers.Count());//此時只有DBLog滿足註入條件因此logger的個數為1

            var fileLog = new FileLog();
            var fileLogPart = AttributedModelServices.CreatePart(fileLog);
            var partBatch = new CompositionBatch();
            partBatch.AddPart(fileLogPart);//添加FileLog滿足ILog的註入條件

            container.Compose(partBatch);
            
            Console.WriteLine(taskExecutor._loggers.Count());//Recomposition會更新logger的註入依賴,此時的logger個數為2

            Console.ReadKey();
        }
    }

MEF學習總結(4)---Container層