MEF學習總結(4)---Container層
通過AttributeedModelPrograming,我們可以聲明暴露組件,依賴組件,發現組件,但是所有這些需要有一個觸發點。即需要把所有這些組合在一起來協同工作,最終實現依賴註入。這就是Container層所做的事情.
CompositionContainer
CompositionContainer在MEF中負責組合其他元素來實現依賴註入。看看他的一個構造函數:
public CompositionContainer( ComposablePartCatalog catalog,//指明如何發現組件 bool isThreadSafe,//指明是否需要線程安全,這個如果在多線程模型下需要設為trueparams 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層