1、框架中的Catalog
在MEF框架中,包含了4種Catalog,所有的Catalog的是從System.ComponentModel.Composition.Primitives名稱空間下的ComposablePartCatalog抽象類派生下來。
AssemblyCatalog:表示從程序集中搜索部件的目錄。
DirectoryCatalog:表示從文件系統的指定路徑中,搜索程序集,從而搜索部件。
TypeCatalog:表示從指定的類型集合中,去搜索相應的部件。
AggregateCatalog:聚合目錄,可以添加上面所說的所有目錄,從而進行多方面的部件搜索。
直接添加部件到容器:
在CompositionContainer類里里通過重載方法ComposeParts()手動添加每個組成部件。下面的例子里一個LoggerProxy的實例和當前要導入的Program實例一起添加到容器
代碼段
container.ComposeParts(this, new LoggerProxy());
2、自定義Catalog
自定義Catalog和系統實現的Catalog類似,我們通過繼承System.ComponentModel.Composition.Primitives空間下的ComposablePartCatalog類,並且覆寫掉基類的方法即可。
要實現自己的Catalog,必須要覆寫掉Parts屬性,如有特別需要處理的,我們還可以覆寫GetExports方法,此方法默認的調用了Parts屬性,進行進一步的輸出。
例如實現目錄過濾篩選功能:
在使用MEF目錄進行導出部件托管的時候,在某些需求下或許只需要其中的一個部件,這種情況可以通過遍歷部件集合得到。然而MEF也為此提供了一種解決方案,那就是使用目錄過濾篩選功能。MEF中的ComposablePartCatalog類和INotifyComposablePartCatalogChanged接口就是專門用來實現目錄篩選的,可以如下代碼段中演示的對目錄過濾的封裝。
代碼段
public class FilteredCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged { private readonly ComposablePartCatalog _inner; private readonly INotifyComposablePartCatalogChanged _innerNotifyChange; private readonly IQueryable<ComposablePartDefinition> _partsQuery; public FilteredCatalog(ComposablePartCatalog inner, Expression<Func<ComposablePartDefinition, bool>> expression) { _inner = inner; _innerNotifyChange = inner as INotifyComposablePartCatalogChanged; _partsQuery = inner.Parts.Where(expression); } public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed { add { if (_innerNotifyChange != null) _innerNotifyChange.Changed += value; } remove { if (_innerNotifyChange != null) _innerNotifyChange.Changed -= value; } } public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing { add { if (_innerNotifyChange != null) _innerNotifyChange.Changing += value; } remove { if (_innerNotifyChange != null) _innerNotifyChange.Changing -= value; } } public override System.Linq.IQueryable<ComposablePartDefinition> Parts { get { return _partsQuery; } } }
3、綜合示例
解決方案如下:
其中MEFParts為一個類庫項目,並且生成輸出路徑是在MyConsoleMEF輸出路徑下的Parts目錄中。
Program中,我們輸出了所有的Part,代碼如下:
代碼段
class Program { private static CompositionContainer container; [ImportMany] public ILogger[] Loggers { get; private set; } static void Main(string[] args) { Program p = new Program(); //AssemblyCatalog:表示從程序集中搜索部件的目錄 var assemblyCatalog = new AssemblyCatalog(typeof(Program).Assembly); //相當於var assemblyCatalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()); //DirectoryCatalog:表示從文件系統的指定路徑中,搜索程序集,從而搜索部件 var directoryCatalog = new DirectoryCatalog(AppDomain.CurrentDomain.BaseDirectory + "\\Parts", "*.dll"); //TypeCatalog:表示從指定的類型集合中,去搜索相應的部件 var typeCatalog = new TypeCatalog(typeof(ConsoleLogger)); //AggregateCatalog:聚合目錄,可以添加上面所說的所有目錄,從而進行多方面的部件搜索 var aggregateCatalog = new AggregateCatalog(assemblyCatalog, directoryCatalog, typeCatalog); container = new CompositionContainer(aggregateCatalog); var exports = container.GetExports<ILogger>(); foreach (var exportValue in exports) { Console.WriteLine(exportValue.Value.GetType()); } Console.Read(); } }
相關閱讀: