MEF框架学习之旅(三)组合
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(); } }
相关阅读: