[MEF]第05篇 MEF的目录(Catalog)筛选

一、演示概述

本示例演示如何使用MEF提供的目录(Catalog)的扩展机制实现可过滤导出部件的自定义目录类。主要是通过继承ComposablePartCatalog基类,并实现接口INotifyComposablePartCatalogChanged来完成的。

相关下载(屏幕录像)http://yunpan.cn/cVkvuUNfuDtTX  访问密码 567d

温馨提示:如果屏幕录像和代码不能正常下载,可站内留言,或发邮件到[email protected]

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

二、自定义部件目录类Catalog

在MEF中,除了可以使用自身提供的注入AggregateCatalog、AssemblyCatalog、DirectoryCatalog这样的目录类以外,也可以自己定义目录类。

自定义目录类需要继承自ComposablePartCatalog类,并实现接口INotifyComposablePartCatalogChanged即可。如下面所示的代码:

public class FilteredCatalog : ComposablePartCatalog, INotifyComposablePartCatalogChanged
{
    #region Private Fields

    private readonly ComposablePartCatalog m_ComposablePartCatalog;
    private readonly INotifyComposablePartCatalogChanged m_NotifyComposablePartCatalogChanged;
    private readonly IQueryable<ComposablePartDefinition> m_Parts;

    #endregion

    #region Constructors

    /// <summary>
    /// 默认构造函数。
    /// </summary>
    /// <param name="composablePartCatalog">包含了所有导出部件的目录Catalog。</param>
    /// <param name="expression">筛选条件表达式。</param>
    public FilteredCatalog(ComposablePartCatalog composablePartCatalog, Expression<Func<ComposablePartDefinition, bool>> expression)
    {
        m_ComposablePartCatalog = composablePartCatalog;
        m_NotifyComposablePartCatalogChanged = composablePartCatalog as INotifyComposablePartCatalogChanged;
        m_Parts = composablePartCatalog.Parts.Where(expression);
    }

    #endregion

    #region INotifyComposablePartCatalogChanged

    /// <summary>
    /// 部件目录Catalog已经改变后触发的事件。
    /// </summary>
    public event EventHandler<ComposablePartCatalogChangeEventArgs> Changed
    {
        add
        {
            if (m_NotifyComposablePartCatalogChanged != null)
            {
                m_NotifyComposablePartCatalogChanged.Changed += value;
            }
        }
        remove
        {
            if (m_NotifyComposablePartCatalogChanged != null)
            {
                m_NotifyComposablePartCatalogChanged.Changed -= value;
            }
        }
    }

    /// <summary>
    /// 部件目录Catalog正在发生改变时触发的事件。
    /// </summary>
    public event EventHandler<ComposablePartCatalogChangeEventArgs> Changing
    {
        add
        {
            if (m_NotifyComposablePartCatalogChanged != null)
            {
                m_NotifyComposablePartCatalogChanged.Changing += value;
            }
        }
        remove
        {
            if (m_NotifyComposablePartCatalogChanged != null)
            {
                m_NotifyComposablePartCatalogChanged.Changing -= value;
            }
        }
    }

    #endregion

    #region ComposablePartCatalog

    /// <summary>
    /// 获取目录中包含的部件定义。经过构造函数中的表达式过滤后,已经是传入目录Catalog对象中的一部分导出部件了。
    /// </summary>
    public override IQueryable<ComposablePartDefinition> Parts
    {
        get { return m_Parts; }
    }

    #endregion
}

上述代码中概括来说包含如下几点内容:

1、构造函数传递了基础目录Catalog对象,这个目录对象可能包含了很多的导出部件,我们要实现的目录过滤类FilteredCatalog就是基于这个目录进行过滤的,它是个全集,而FilteredCatalog是它的子集。另外一个参数是过滤表达式,过滤条件由调用者来编写,至于内部过滤办法实际还是LINQ提供的Where()方法。

2、对于接口INotifyComposablePartCatalogChanged的实现,实际上是和基础目录Catalog对象的事件关联在一起,即当基础目录对象发生改变时,目录过滤类FilteredCatalog也将会收到相应的通知。

3、重写了基类ComposablePartCatalog的Parts集合属性,该属性返回的就是该目录中包含部件定义,凡是在目录中需要被暴露的部件定义都是通过该集合返回的。因此,上述代码中将过滤后的部件定义通过该属性返回。

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

三、使用自定义目录类Catalog

如下代码所示:

// 获取所需的部件。
DirectoryCatalog catalog = new DirectoryCatalog("controls");
CompositionContainer container = new CompositionContainer(catalog);

// 过滤Catalog,生成子组合容器。
FilteredCatalog filteredCatalog = new FilteredCatalog(catalog,
    o=>o.Metadata.ContainsKey("UC") && o.Metadata["UC"].ToString() == "BB");
CompositionContainer filteredContainer = new CompositionContainer(filteredCatalog, container);

UserControl userControl = filteredContainer.GetExportedValue<UserControl>();
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

时间: 2024-12-20 18:26:00

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

[MEF]第01篇 MEF使用入门

一.演示概述 此演示初步介绍了MEF的基本使用,包括对MEF中的Export.Import和Catalog做了初步的介绍,并通过一个具体的Demo来展示MEF是如何实现高内聚.低耦合和高扩展性的软件架构.演示中,针对于IBookService接口,有3个不同版本的实现,分别是ComputerBookServiceImp.HistoryBookServiceImp和MathBookServiceImp,然后通过MEF的导入导出及组装机制,分别在这3个版本的实现间替换,而这种替换并未通过配置文件之类

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

一.演示概述 此演示介绍了MEF如何使用ImportMany特性同时导入多个与相同约束相匹配的导出部件,并且介绍了目录服务(Catalog),该服务告知MEF框架可以在什么地方去搜寻与指定约束匹配的导出部件,即导出部件位于什么地方. 相关下载(屏幕录像.代码):http://yunpan.cn/cVdN5JHeQrJgI 访问密码 065d 温馨提示:如果屏幕录像和代码不能正常下载,可站内留言,或发邮件到[email protected] 欢迎有兴趣研究.NET相关技术的网友加QQ群:18507

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

一.演示概述 此演示介绍了MEF的延迟加载及元数据相关的内容. 在实际的设计开发中,存在着某些对象是不需要在系统运行或者附属对象初始化的时候进行实例化的, 只需要在使用到它的时候才会进行实例化,这种方式就可以理解为对象的迟延初始化,或者叫迟延加载. 对于提升系统的性能大有裨益呀! 另外,还可以为导出的部件添加元数据,以便在代码中提供更加灵活的扩展办法,或获取更多的相关信息.甚至,还可以自定义元数据的接口,无论是定义还是使用都非常的方便. 相关下载(屏幕录像):http://yunpan.cn/c

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

一.演示概述 此演示介绍了如何为Export指定导出的协议名和类型,以及如何为Import指定导入的协议名和类型,只有确保导出和导入的协议名和类型相匹配了,才能注入成功,否则注入就会失败. 相关下载(屏幕录像):http://yunpan.cn/cZIxLTJgGhpvp  访问密码 3b86 在线播放: 温馨提示:如果屏幕录像和代码不能正常下载,可站内留言,或发邮件到[email protected] 欢迎有兴趣研究.NET相关技术的网友加QQ群:18507443 二.关键代码 包含协议名和类

Python开发【第一篇】:目录

本系列博文改编自武沛齐老师的原创博文,主要包含  Python基础.前端开发.Web框架.缓存以及队列等内容 ,用于学习记录成长!!! Python开发[第一篇]:目录 Python开发[第二篇]:初识Python

Python自动化基础【第一篇】:目录

本系列博文包含 Python基础.前端开发.Web框架.缓存以及队列等,希望可以给正在学习编程的童鞋提供一点帮助!!! Python自动化基础[第一篇]:目录 Python自动化基础[第二篇]:初识Python Python自动化基础[第三篇]:Python基本数据类型 Python自动化基础[第四篇]:Python基础之函数 Python自动化基础[第五篇]:Python基础之杂货铺 Python自动化基础[第六篇]:模块 Python自动化基础[第七篇]:面向对象 Python自动化基础[第

shell脚本第二篇——将指定目录下大于200K的文件移动到/tmp下

shell脚本第二篇--将指定目录下大于200K的文件移动到/tmp下 # vim  /tmp/files.sh #!/bin/bash #将指定目录下大于200K的文件移动到/tmp下 read  -p  "请输入您要将目录下大于200K文件移动的目录路径:" $1 for FILE in `ls  $1` do if [ -f  $FILE ] ; then if [ `ls -l $FILE | awk `{print $5}` -gt 204800 ] ; then mv  $

Python 全栈开发【第一篇】:目录

Python 全栈开发[第0篇]:目录 第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基础语法入门 Python 全栈开发[第三篇]:数据类型.字符编码.文件操作 第二阶段:函数编程&常用标准库 Python 全栈开发[第四篇]:函数.递归.生成器.迭代器 Pyhton 全栈开发[第五篇]:常用模块学习 第三阶段:面向对象编程&网络编程基础 Python 全栈开发[第六篇]:面向对象

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

一.演示概述 本演示介绍了MEF的生命周期管理,重点介绍了导出部件的三种创建策略,分别是:CreationPolicy.Any.CreationPolicy.Shared.CreationPolicy.NonShared. 相关下载(屏幕录像):http://yunpan.cn/cjZEXHY8N3D6z  访问密码 3912 温馨提示:如果屏幕录像和代码不能正常下载,可站内留言,或发邮件到[email protected] 欢迎有兴趣研究.NET相关技术的网友加QQ群:18507443 二.部