MEF在.net中实现插件功能

2015-10-10 (2015-10-10更新)

MEF简介

MEF 可以比较方便的在.net程序中实现插件技术,相比MAF等技术要简单易用,对于小型项目建议使用MEF。MEF通过接口暴露公开方法,插件内继承接口的类可以通过[Export]特性公开,宿主程序通过建立接口类型的属性(必须有[Import]特性)调用插件方法。插件可以和主程序不在同一个程序集,插件也可以在需要的任何时候添加到主程序。

MEF组成

MEF主要有4个部分组成

  • 接口部分:定义插件接口
  • 出口部分:也就是插件,其实就是实现了插件接口并带有Export特性的类
  • 入口部分:通过入口可以调用插件对象,带有Import特性且声明为插件接口类型的属性
  • 容器部分:容器加载出口部分也就是插件,并把插件映射到入口部分

在容器把出口部分映射到入口部分后,宿主程序可以通过调用入口部分调用插件对象或函数。

MEF使用步骤

定义插件接口

根据需要定义Interface,Interface主要用于暴露插件的属性或方法。在接口中也可以定义获取插件中的UI控件、菜单项的方法或属性。

编写入口/import

  • 依赖接口部分
  • 在入口部件里声明接口类型的属性或方法,并添加Import特性

编写出口/export/插件

  • 依赖接口部分
  • 编写至少一个实现接口的类,并添加Export特性
  • 可以在单独的程序集/dll里
  • 可以在程序完成后,无源代码的情况下加入更多的出口,即程序可以动态加载插件

通过Batch可以动态加载或卸载出口部件(出口部件是一个可以包含插件程序集信息列表的类)。

建立容器container

  • 容器依赖入口部件,不依赖出口部件
  • 一般container在宿主程序内
  • 创建代码为:container=new CompostionContainer(category);,需要先建立类别catelog
    • category里包含出口部件/插件信息
    • DirectoryCatelog:从指定目录获取部件
    • AssemblyCtelog:

容器组合出口/export和入口/import(映射出口到入口)

  • composeParts(入口部件实例,可以是数组)
  • compose(batch)

宿主程序调用入口

  • 依赖入口部件
  • 依赖容器,因为宿主运行插件时需要调用容器先执行compose操作
  • 通过入口部件实例直接调用带Import特性的属性或方法
  • 所有入口都映射到了出口程序上才能正确运行,否则会抛出异常

组织结构

  • 插件在单独的程序集中
  • 插件接口推荐放在单独的程序集中,因为出口部分和入口部分都依赖接口部分
  • 一般情况下宿主程序直接调用容器和入口部分(即三者在同一个程序集中)
    • 入口和容器不在宿主程序集也可以通过reference调用,不一定必须在同一个程序集

代码实例

待续…

Fork me on GitHub