MEF基础指南——MEF导入导出

文章缘起

要说写MEF中的导入导出,我想没有哪一篇文章可以比得上微软的官方文档了(至少是我看到的里面没有)。
个人强烈建议看MEF导入导出的人去看微软官方文档,文档地址:

个人喜欢用 Microsoft Help查看器(Help Viewer) 离线查看,如果你也喜欢这样,你可以直接在里面搜索MEF,找到特性化编程模型概述即可。

既然微软官方文档已经很完善了,那本文自然不会在写一遍,故本文更倾向与一篇快速索引参考文。

快速参考

导入导出基础

  1. 无参数导入导出,默认使用当前类或接口,示例如下:

示例中最后a有效,而ia无效;

    public interface IA { }

    /// <summary>
    /// 等价于 [Export(typeof(A))]
    /// </summary>
    [Export]
    public class A : IA { }

    public class UseA
    {
        /// <summary>
        /// 等价于 [Import(typeof(A))]
        /// </summary>
        [Import]
        public A a { get; set; }

        /// <summary>
        /// 等价于 [Import(typeof(IA))]
        /// </summary>
        [Import]
        public IA ia { get; set; }
    }
  1. 含参数导入导出,要求类型和协定名完全匹配,未指定类型时,同上,使用当前声明的类或接口。

如下示例中,最终ib有效 ,而b是无效的。

    public interface IB { }

    [Export(typeof(IB))]
    public class B : IB { }

    public class UseB
    {
        [Import]
        public B b { get; set; }

        [Import]
        public IB ib { get; set; }
    }
  1. 延迟导入及导入多个;其中匹配类型时,均使用繁星内的类型。

在如下示例中,三个导入均有效。其中ImportMany主要用于多个具有相同协定名和类型的导出,如你有两个类使用了相同的类型和协定,用Import是会报错的,此时可以用ImportMany来处理。

    public interface IC { }

    [Export(typeof(IC))]
    public class C : IC { }

    public class UseC
    {
        [Import]
        public Lazy<IC> ic { get; set; }

        [ImportMany]
        public IEnumerable<IC> iclist { get; set; }

        [ImportMany]
        public IEnumerable<Lazy<IC>> icllist { get; set; }
    }

元数据

元数据可以简单理解为:针对具有相同协定和类型的导出,添加元数据来区分它们。

继承

在MEF中使用InheritedExport来设置继承导出,在继承结构中,导出的匹配类型为父类/接口的类型,示例如下:

在如下代码中,最后id是有效的,d是无效的,即类型D的导出继承ID,使用的类型为ID。

    [InheritedExport]
    public interface ID { }

    public class D : ID { }

    public class UseD
    {
        [Import]
        public D d { get; set; }

        [Import]
        public ID id { get; set; }
    }

结语

本文主要列出了最常用的导入导出参考,详细信息及更多扩展内容还是建议看微软官方文档:特性化编程模型概述 (MEF)


奇葩史