之前在使用Prism框架时接触到了可扩展性框架MEF(Managed Extensibility Framework),体验到MEF带来的极大的便利性与可扩展性。

此篇将编写一个可组合的应用程序,帮助大家快速熟悉MEF并将其应用于实际项目中。

有关MEF中的名词含义及功能实现,请大家移步:火车票

介绍下将要编写的Demo程序(下图),使用winform开发。

  • 通过组合操作,程序动态加载可用部件进行组合操作。
  • 通过解体操作,程序卸载所加载的所有部件。

新建项目后需引用程序集:

System.ComponentModel.Composition

主程序的核心代码如下:

  public partial class Form1 : Form, IPartImportsSatisfiedNotification
  {
[ImportMany(AllowRecomposition = true)]
private IEnumerable<Lazy<IPlugin, IPluginMetadata>> plugins; private AggregateCatalog catalog;
private CompositionContainer container;
public Form1()
{
InitializeComponent();
if (catalog == null)
catalog = new AggregateCatalog();
this.container = new CompositionContainer(catalog);
this.container.ComposeParts(this);
} #region Implementation of IPartImportsSatisfiedNotification
public void OnImportsSatisfied()
{
flowLayoutPanel1.Controls.Clear();
if (plugins != null && plugins.Count() != )
{
plugins.ToList().ForEach((a) =>
{
Button btn = new Button();
btn.Cursor = System.Windows.Forms.Cursors.Hand;
btn.Width = ;
btn.Height = ;
btn.Text = a.Metadata.ThePluginName;
btn.Click += (d, b) => { a.Value.Run(); };
flowLayoutPanel1.Controls.Add(btn);
});
}
}
#endregion public void CompositionAction()
{
catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
}
......
  }

1. IPartImportsSatisfiedNotification接口 : 在组件导入完成后,调用该接口中的方法(OnImportsSatisfied)。

2. MEF中最常用目录有三种:程序集目录(AssemblyCatalog),文件目录(DirectoryCatalog),聚合目录(AggregateCatalog)

程序集目录(AssemblyCatalog): 顾名思义可以向目录中添加程序集已存在类型中寻找可用于导入的部件。

var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());

文件夹目录(DirectoryCatalog):从文件夹中寻找可用于导入的部件

var catalog = new DirectoryCatalog("Extensions");

聚合目录(AggregateCatalog):可以向聚合目录包含上述两种方式

var catalog = new AggregateCatalog(
new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()),
new DirectoryCatalog("Extensions"));

3. CompositionContainer : 组合容器,管理部件的组合并提供了一系列用于创建部件实例扩展方法等,详细资料

4. 目录与容器的一般使用方法:

    var catalog = new AggregateCatalog();
var container = new CompositionContainer(catalog);
container.ComposeParts(this);

5. 导入:ImportAttribute 与 ImportManyAttribute

用于以下三种用途:字段,属性,方法

[import]
private IData _data; [import]
public IData Data{set;get;} [import]
public Action ClickAction;

ImportManyAttribute : 通过组合容器将所有符合契约的导出进行填充 (真别扭,说白了就是导入多个)

[ImportMany]
private IEnumerable<IPlugin> plugins;

AllowRecomposition : 是否允许重组

AllowRecomposition = true : 比如在程序运行的过程中,动态向聚合目录中添加可导出的部件,可以引发重组操作

catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));

需要注意的是:DirectoryCatalog 不会引发重组操作,可通过Refresh方法指定重组的策略。

6. System.Lazy<T> : MEF提供延迟导入。

下面来看一下,插件式如何实现的:

  [ExportPluginAttribute(typeof(IPlugin), ThePluginName = "TheFristPlugin")]
public class TheFristPlugin : IPlugin
{
public TheFristPlugin()
{
this.TheName = "TheFristPlugin";
}
#region Implementation of IPlugin public string TheName { get; set; } public void Run()
{
MessageBox.Show("TheFristPlugin");
} #endregion
}

1. 简单说一下:导入与导出之前的关系

一个基于MEF开发的可扩展的程序,在容器中必然有很多的导出(Export),而这些Export又是怎么样找到自己的归宿呢。

Export 与 Import 依靠一种契约,来确定对方是否是自己的兄弟,说白了就是接口,比如上述程序所定义的IPlugin接口

    public interface IPlugin
{
void Run();
}

使用 ExportAttribute 特性导出:

 [Export("count")]
public int count{ get{return ;} } [Export(typeof(Action))]
public void SendMsg(){return;} [Export]
public class Person{}

有一个需求,主程序要求插件必须要指定插件名称:

1. 在IPlugin接口中定义:Name字段

2. 使用元数据

3. 使用自定义导出特性(与第二种方案类似)

如何使用元数据?

1.定义元数据视图,此处视图使用接口类型

 public interface IPluginMetadata
{
string ThePluginName { get; }
}

2. 导出部件时,使用ExportMetaData特性

[ExportMetadata("ThePluginName", "TheFivePlugin")]
[Export(typeof(mef.test.wform.Interface.IPlugin))]
public class TheFivePlugin : mef.test.wform.Interface.IPlugin
{
public void Run()
{
MessageBox.Show("TheFivePlugin");
}
}

3. 导入元数据

[ImportMany(AllowRecomposition = true)]
private IEnumerable<Lazy<IPlugin, IPluginMetadata>> plugins;

4. 访问元数据

Lazy<T,TMetadata>.Value.Metadata

结束

到此为止,MEF 基本内容已讲解结束,如果有遗漏也请博友留言指出。

文章中很多都是白话,非官方语言,怎么理解的就怎么写,如果有不妥之处,还望各位博友指出。

新年快乐

浅谈可扩展性框架:MEF的更多相关文章

  1. 手撸ORM浅谈ORM框架之基础篇

    好奇害死猫 一直觉得ORM框架好用.功能强大集众多优点于一身,当然ORM并非完美无缺,任何事物优缺点并存!我曾一度认为以为使用了ORM框架根本不需要关注Sql语句如何执行的,更不用关心优化的问题!!! ...

  2. 手撸ORM浅谈ORM框架之Add篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  3. 手撸ORM浅谈ORM框架之Update篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  4. 手撸ORM浅谈ORM框架之Delete篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  5. 手撸ORM浅谈ORM框架之Query篇

    快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...

  6. 【SSH学习笔记】浅谈SSH框架

    说在前面 本学期我们有一门课叫做Java EE,由陈老师所授,主要讲的就是Java EE 中的SSH框架. 由于陈老师授课风格以及自己的原因导致学了整整一学期不知道在讲什么,所以才有了自己重新学习总结 ...

  7. 浅谈angular框架

    最近新接触了一个js框架angular,这个框架有着诸多特性,最为核心的是:MVVM.模块化.自动化双向数据绑定.语义化标签.依赖注入,以上这些全部都是属于angular特性,虽然说它的功能十分的强大 ...

  8. 13.Object-C--浅谈Foundation框架常用的结构体

    ------- android培训.iOS培训.期待与您交流! ---------- 昨天学习了Foundation框架中常用的结构体,下面我简单的总结一下,如果错误麻烦请留言指正,谢谢! Found ...

  9. 2014-07-29 浅谈MVC框架中Razor与ASPX视图引擎

    今天是在吾索实习的第15天.随着准备工作的完善,我们小组将逐步开始手机端BBS的开发,而且我们将计划使用MVC框架进行该系统的开发.虽然我们对MVC框架并不是非常熟悉,或许这会降低我们开发该系统的效率 ...

随机推荐

  1. net中序列化读写xml

    参考http://www.cnblogs.com/fish-li/archive/2013/05/05/3061816.html 我们可以直接使用XmlTextReader.XmlDocument.X ...

  2. IOS 核心动画之CAKeyframeAnimation - iBaby

    - IOS 核心动画之CAKeyframeAnimation - 简单介绍 是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation ...

  3. The storage wars: Shadow Paging, Log Structured Merge and Write Ahead Logging

    The storage wars: Shadow Paging, Log Structured Merge and Write Ahead Logging previous: Seek, and yo ...

  4. 基础篇-Windows消息机制

    1在介绍Windows 消息运行机制之前,首先介绍一下消息的概念: 消息(Message)指的就是Windows 操作系统发给应用程序的一个通告[5],它告诉应用程序某个特定的事件发生了.比如,用户单 ...

  5. 计算机网络(3)-----IP数据报格式

    IP数据报(IP Datagram) 格式 解析 (1)版本 占4位,指IP协议的版本.通信双方使用的IP协议版本必须一致.目前广泛使用的IP协议版本号为4(即IPv4). (2)首部长度 占4位,可 ...

  6. QuartZ.net 常用配置说明

    配置文件说明 app.config中的quartz部分 <quartz> <!-- configure Thread Pool--> <addkey="quar ...

  7. 在 Vultr VPS 中 以 Debian 8 i386 (jessie) 为 操作系统 平台 手动 搭建 PPTP VPN 全过程

    更新服务器并安装 PPTP 服务  apt-get update apt-get upgrade apt-get install pptpd 编辑 /etc/pptpd.conf 找到 #locali ...

  8. (C语言)结构体成员的引用->(箭头)和 .(点)

    关于结构体成员的引用有这样的规律: 箭头(->):左边必须为指针: 点号(.):左边必须为实体. 那么如果一个结构体指针引用一个成员,这个成员又是一个结构体(并且是一个实体),那么如果要引用这个 ...

  9. GCC编译器编译链接

    在gcc编译器环境下,常见的文件扩展名的含义如下: .c:C源程序,经过预编译后的源程序也为.c文件,它可以通过-E参数输出. .h:头文件 .s:经过编译得到的汇编程序代码,它可以通过-S参数输出. ...

  10. SQL升级脚本实现按版本差异化升级

    目前的项目里面,升级脚本是一个SQL文件,无论软件从哪个版本升级,都会把SQL文件里面的语句全部执行一遍,这样存在两个问题: 1.SQL升级文件很庞大,几M很常见,导致文件的加载很慢: 2.重复执行脚 ...