之前在使用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. iOS开发拓展篇—应用之间的跳转和数据传递

    iOS开发拓展篇—应用之间的跳转和数据传 说明:本文介绍app如何打开另一个app,并且传递数据. 一.简单说明 新建两个应用,分别为应用A和应用B. 实现要求:在appA的页面中点击对应的按钮,能够 ...

  2. C#压缩文件夹

    using System;using System.Collections.Generic;using System.Text; ///第三方dllusing ICSharpCode.SharpZip ...

  3. ros使用rplidar hector_mapping建地图

    ros中建地图方式有两种: 首先1.首先下载hector_slam包到你工作空间的src下 命令: cd ~/catkin/src git clone https://github.com/tu-da ...

  4. vs2008编译openssl问题

    运行openssl demo 时,debug 版本正常,release 版本报异常:OPENSSL_Uplink(585E6000,08): no OPENSSL_Applink .demo 编译环境 ...

  5. Rhel6-pacemaker+drbd配置文档

    系统环境: rhel6 x86_64 iptables and selinux disabled 主机: 192.168.122.119 server19.example.com 192.168.12 ...

  6. 一台服务器发布多个tomcat并注册服务名办法

    修改服务名称 打开Tomcat7.0.65_1/bin/service.bat  修改注册服务名称 当然这个名字自己改 比如Tomcat7_2 原始文件:   set SERVICE_NAME=Tom ...

  7. 变量声明提升 Vs. 函数声明提升

    1. 变量声明提升 先看以下代码: 1)var in_window = "a" in window; console.log(in_window); 2)var in_window ...

  8. HttpContext.Current.Cache 和HttpRuntime.Cache的区别

    先看MSDN上的解释:      HttpContext.Current.Cache:为当前 HTTP 请求获取Cache对象.      HttpRuntime.Cache:获取当前应用程序的Cac ...

  9. xpcall 安全调用

    -- xpall (调用函数f, 错误函数fe[, 参数]) function fun(a,b)   -- 这里的参数没什么实际作用,就是展示下用法    return a / bend -- xpc ...

  10. VS2010 刷新工具箱(刷新自定义控件)

    有时候自己自定义了控件,定义完后却不见工具箱中刷新出来自定义的控件,解决方案有了三种: 点评:在项目中增加了几个自定义控件,想在窗口上添加时却发现工具箱根本就没有些控件,晕了.记得2008都可以自动出 ...