一、演示概述
本示例演示如何使用MEF提供的目录(Catalog)的扩展机制实现可过滤导出部件的自定义目录类。主要是通过继承ComposablePartCatalog基类,并实现接口INotifyComposablePartCatalogChanged来完成的。
相关下载(屏幕录像)http://yunpan.cn/cVkvuUNfuDtTX  访问密码 567d
温馨提示:如果屏幕录像和代码不能正常下载,可站内留言,或发邮件到524130780@QQ.COM

欢迎有兴趣研究.NET相关技术的网友加QQ群:18507443

二、自定义部件目录类Catalog
在MEF中,除了可以使用自身提供的注入AggregateCatalog、AssemblyCatalog、DirectoryCatalog这样的目录类以外,也可以自己定义目录类。
自定义目录类需要继承自ComposablePartCatalog类,并实现接口INotifyComposablePartCatalogChanged即可。如下面所示的代码:

  1. public class FilteredCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
  2. {
  3. #region Private Fields
  4. private readonly ComposablePartCatalog m_ComposablePartCatalog;
  5. private readonly INotifyComposablePartCatalogChanged m_NotifyComposablePartCatalogChanged;
  6. private readonly IQueryable<ComposablePartDefinition> m_Parts;
  7. #endregion
  8. #region Constructors
  9. /// <summary>
  10. /// 默认构造函数。
  11. /// </summary>
  12. /// <param name="composablePartCatalog">包含了所有导出部件的目录Catalog。</param>
  13. /// <param name="expression">筛选条件表达式。</param>
  14. public FilteredCatalog(ComposablePartCatalog composablePartCatalog, Expression<Func<ComposablePartDefinition, bool>> expression)
  15. {
  16. m_ComposablePartCatalog = composablePartCatalog;
  17. m_NotifyComposablePartCatalogChanged = composablePartCatalog as INotifyComposablePartCatalogChanged;
  18. m_Parts = composablePartCatalog.Parts.Where(expression);
  19. }
  20. #endregion
  21. #region INotifyComposablePartCatalogChanged
  22. /// <summary>
  23. /// 部件目录Catalog已经改变后触发的事件。
  24. /// </summary>
  25. public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed
  26. {
  27. add
  28. {
  29. if (m_NotifyComposablePartCatalogChanged != null)
  30. {
  31. m_NotifyComposablePartCatalogChanged.Changed += value;
  32. }
  33. }
  34. remove
  35. {
  36. if (m_NotifyComposablePartCatalogChanged != null)
  37. {
  38. m_NotifyComposablePartCatalogChanged.Changed -= value;
  39. }
  40. }
  41. }
  42. /// <summary>
  43. /// 部件目录Catalog正在发生改变时触发的事件。
  44. /// </summary>
  45. public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing
  46. {
  47. add
  48. {
  49. if (m_NotifyComposablePartCatalogChanged != null)
  50. {
  51. m_NotifyComposablePartCatalogChanged.Changing += value;
  52. }
  53. }
  54. remove
  55. {
  56. if (m_NotifyComposablePartCatalogChanged != null)
  57. {
  58. m_NotifyComposablePartCatalogChanged.Changing -= value;
  59. }
  60. }
  61. }
  62. #endregion
  63. #region ComposablePartCatalog
  64. /// <summary>
  65. /// 获取目录中包含的部件定义。经过构造函数中的表达式过滤后,已经是传入目录Catalog对象中的一部分导出部件了。
  66. /// </summary>
  67. public override IQueryable<ComposablePartDefinition> Parts
  68. {
  69. get { return m_Parts; }
  70. }
  71. #endregion
  72. }

上述代码中概括来说包含如下几点内容:
1、构造函数传递了基础目录Catalog对象,这个目录对象可能包含了很多的导出部件,我们要实现的目录过滤类FilteredCatalog就是基于这个目录进行过滤的,它是个全集,而FilteredCatalog是它的子集。另外一个参数是过滤表达式,过滤条件由调用者来编写,至于内部过滤办法实际还是LINQ提供的Where()方法。
2、对于接口INotifyComposablePartCatalogChanged的实现,实际上是和基础目录Catalog对象的事件关联在一起,即当基础目录对象发生改变时,目录过滤类FilteredCatalog也将会收到相应的通知。
3、重写了基类ComposablePartCatalog的Parts集合属性,该属性返回的就是该目录中包含部件定义,凡是在目录中需要被暴露的部件定义都是通过该集合返回的。因此,上述代码中将过滤后的部件定义通过该属性返回。

定义好了过滤类,接下来就是如何使用它了。

三、使用自定义目录类Catalog
如下代码所示:

  1. // 获取所需的部件。
  2. DirectoryCatalog catalog = new DirectoryCatalog("controls");
  3. CompositionContainer container = new CompositionContainer(catalog);
  4. // 过滤Catalog,生成子组合容器。
  5. FilteredCatalog filteredCatalog = new FilteredCatalog(catalog,
  6. o=>o.Metadata.ContainsKey("UC") && o.Metadata["UC"].ToString() == "BB");
  7. CompositionContainer filteredContainer = new CompositionContainer(filteredCatalog, container);
  8. UserControl userControl = filteredContainer.GetExportedValue<UserControl>();
  9. this.MainContentControl.Content = userControl;

首先通过DirectoryCatalog类获取到应用程序根目录下controls子文件夹中的所有部件定义,并以此生成顶级组合容器container(类型为CompositionContainer)。
然后使用自定义目录过滤类FilteredCatalog对DirectoryCatalog目录中的部件定义进行过滤,并生成子组合容器filteredContainer(类型为CompositionContainer)。
最后通过组合容器的GetExportedValue<T>()方法获取指定协议类型的导出部件。需要说明的是,如果组合容器中没有对应协议类型的导出部件则会引发异常。

可通过如下地址获取完整的示例代码和屏幕录像文件。

四、相关资源
1、MSDN官方资料:http://msdn.microsoft.com/zh-cn/library/dd460648(v=vs.110).aspx

2、参考了微软MVP Bēniaǒ的文章《MEF程序设计指南七:使用目录(Catalog)动态装载xap与目录筛选(Filtered Catalog)》,访问地址:http://www.cnblogs.com/beniao/archive/2010/07/26/1782622.html

[MEF]第05篇 MEF的目录(Catalog)筛选的更多相关文章

  1. [MEF]第01篇 MEF使用入门

    一.演示概述 此演示初步介绍了MEF的基本使用,包括对MEF中的Export.Import和Catalog做了初步的介绍,并通过一个具体的Demo来展示MEF是如何实现高内聚.低耦合和高扩展性的软件架 ...

  2. [MEF]第04篇 MEF的多部件导入(ImportMany)和目录服务

    一.演示概述此演示介绍了MEF如何使用ImportMany特性同时导入多个与相同约束相匹配的导出部件,并且介绍了目录服务(Catalog),该服务告知MEF框架可以在什么地方去搜寻与指定约束匹配的导出 ...

  3. [MEF]第03篇 MEF延迟加载导出部件及元数据

    一.演示概述此演示介绍了MEF的延迟加载及元数据相关的内容.在实际的设计开发中,存在着某些对象是不需要在系统运行或者附属对象初始化的时候进行实例化的,只需要在使用到它的时候才会进行实例化,这种方式就可 ...

  4. [MEF]第02篇 MEF的导入导出契约

    一.演示概述此演示介绍了如何为Export指定导出的协议名和类型,以及如何为Import指定导入的协议名和类型,只有确保导出和导入的协议名和类型相匹配了,才能注入成功,否则注入就会失败.相关下载(屏幕 ...

  5. Python开发【第一篇】:目录

    本系列博文包含 Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习编程的童鞋提供一点帮助!!! Python开发[第一篇]:目录 Python开发[第二篇]:初识Python ...

  6. Swift LeetCode 目录 | Catalog

    请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift    说明:题目中含有$符号则为付费题目. 如 ...

  7. Python 全栈开发【第0篇】:目录

    Python 全栈开发[第0篇]:目录   第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基 ...

  8. MEF初体验之八:过滤目录

    当在使用子容器的时候,基于某些具体标准来过滤目录可能是重要的.例如,基于部件的创建策略来过滤是很常见的.下面的代码片段演示了如何构建这种特别方法: var catalog = new Assembly ...

  9. 第06篇 MEF部件的生命周期(PartCreationPolicy)

    一.演示概述 本演示介绍了MEF的生命周期管理,重点介绍了导出部件的三种创建策略,分别是:CreationPolicy.Any.CreationPolicy.Shared.CreationPolicy ...

随机推荐

  1. 开机启动服务(ftp、apache、mysql)

    当linux服务器开机时,会将 /etc/rc.d/rc.local 中的指令全部执行一遍, 因此将相应服务的启动指令放到该shell脚本中即可实现开机启动效果; 在 /etc/rc.d/rc.loc ...

  2. Java 注解(Annotation)秒懂,你可以这样学,

    文章开头先引入一处图片. 这处图片引自老罗的博客.为了避免不必要的麻烦,首先声明我个人比较尊敬老罗的.至于为什么放这张图,自然是为本篇博文服务,接下来我自会说明.好了,可以开始今天的博文了. Anno ...

  3. oracle 11g安装过程中问题:移动bin\oralbac11.dll 到bin\oralbac11.dll.dbl出错

    解决方法: 直接找到oralbac11.dll.dbl这个文件,将其删除即可.   http://blog.sina.com.cn/s/blog_51beaf0e0101000v.html

  4. Back Track5学习笔记

    1.BT5默认用户名:root.密码:toor(公司是yeslabccies) 2.进入图形化界面命令:startx 3.更改密码:sudo passwd root 扫描工具 第一部分网络配置: 4. ...

  5. IOS-CocoaPods制作篇

    作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/20067595 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关 ...

  6. 【Error】SSL InsecurePlatform error when using Requests package

    使用requests时会出席SSL InsecurePlatform error when using Requests package的错误,一般情况下python2.7.10以下的环境会出现此错误 ...

  7. python 黑客书籍 ——扫描+暴力破解

    https://legacy.gitbook.com/book/germey/net-security/details 网络安全 介绍 构建一个端口扫描器 利用Pexpect模拟SSH连接 利用Pxs ...

  8. 文件上传及时显示, 前端js和后端php相互结合使用

    文件读取 javascript 绑定文件上传变化事件 onchange 利用window对象 FileReader 调用方法 readerAsDataURL onload 方法 异步读取 属性:fil ...

  9. 【转】OpenWRT开发自定义应用方法

    [转]OpenWRT开发自定义应用方法 转自:http://blog.csdn.net/rudyn/article/details/38616783 OpenWRT编译成功完成后,所有的产品都会放在编 ...

  10. windows配置redis(转)

    此文章全部是转的,我之前是woidows启动redis无法加载配置找到的:原文链接:http://www.cnblogs.com/smileyearn/articles/4749746.html 在w ...