首页 > 电脑专区 > 电脑教程 >

如何用 MEF 扩展应用程序

来源:互联网 2023-02-21 20:32:00 版权归原作者所有,如有侵权,请联系我们

最近在写一篇关于如何扩展 Visual Studio 编辑器的文章时,用到了 MEF,因此打算写一篇文章提一下这个技术点。本篇文章并不打算详细介绍 MEF,只是一个最简单的入门,相信您在阅读本篇文章后,可以迅速开发出一个可扩展的应用程序。6ik办公区 - 实用经验教程分享!

工具/原料

  • .Net Framework 4 或以上/

简 介

  • 1

    MEF(Managed Extensibility Framework),是微软推出的一款用于搭建可扩展应用程序的框架,起初是独立于 .Net 发布的,后来集成到了 .Net 4.0 中。使用该框架可以非常轻松地扩展一个已发布的应用程序的功能,连 Visual Studio IDE 中的代码编辑器窗口也采用了MEF的思想,因此大大方便了开发人员对编辑器的扩展。6ik办公区 - 实用经验教程分享!

      MEF 可用在任何使用 .NET Framework 的地方。可以在客户端应用程序中使用 MEF(无论应用程序使用的是 Windows 窗体、WPF,还是任何其他技术),也可以在使用 ASP.NET 的服务器应用程序中使用 MEF。6ik办公区 - 实用经验教程分享!

  • 1此文章未经许可获取自百度经验
  • MEF的关键概念

  • 1

    Import6ik办公区 - 实用经验教程分享!

      导入,这里建议作为一个名词来理解,即一个接受者,它可以接受外来的东东。就好比是下图中的盒子,它可以接受其它积木。6ik办公区 - 实用经验教程分享!

    如何用 MEF 扩展应用程序6ik办公区 - 实用经验教程分享!

  • 2

    Export6ik办公区 - 实用经验教程分享!

      导出,同样建议以一个名词来理解,即一个第三方的产物。它就像上图中不同颜色的积木,这些积木不属于这个盒子,但是能被放入盒子中,来丰富盒子的功能。6ik办公区 - 实用经验教程分享!

    如何用 MEF 扩展应用程序6ik办公区 - 实用经验教程分享!

  • 3

    Contract6ik办公区 - 实用经验教程分享!

      协议。要想使盒子能接受积木(比如,圆柱体只能放入圆形的接口中),那这些积木必须符合一定的形状。而这些形状就相当于是应用程序和第三方扩展之间的一个协议。6ik办公区 - 实用经验教程分享!

    如何用 MEF 扩展应用程序6ik办公区 - 实用经验教程分享!

  • 4

    Compose6ik办公区 - 实用经验教程分享!

      组合(动词),即将多个符合协议要求的部件组合在一起,构成一个功能丰富的应用程序。就好比是将不同形状的积木,按照接口的形状组合在一起。6ik办公区 - 实用经验教程分享!

  • 它是如何工作的?

  • 1

    MEF 会动态查找用户所指定的目录,如果发现该目录中的程序集满足协议要求,就会启动自身的组合引擎,然后根据不同的协议约定把这些扩展导入到应用程序内部。6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

  • 用 MEF 实现一个最简单的可扩展应用程序

  • 1

    对几个关键的概念清楚了之后,我们就可以开始实践了。最终的效果是窗体上会动态加载某一目录下的dll,并自动为每个新功能添加一个按钮,当点击按钮就会执行新的功能。6ik办公区 - 实用经验教程分享!

    如何用 MEF 扩展应用程序6ik办公区 - 实用经验教程分享!

  • 2

    首先,定义一个协议。6ik办公区 - 实用经验教程分享!

      这个和普通定义接口没什么两样6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    1 public interface IPlugin6ik办公区 - 实用经验教程分享!

    2 {6ik办公区 - 实用经验教程分享!

    3 string Text { get; }6ik办公区 - 实用经验教程分享!

    4 6ik办公区 - 实用经验教程分享!

    5 void Do();6ik办公区 - 实用经验教程分享!

    6 }6ik办公区 - 实用经验教程分享!

  • 3

    安装接受者6ik办公区 - 实用经验教程分享!

      有了协议之后,就需要给应用程序安一个接受者。让这个应用程序可以通过接受者来获取第三方扩展。MEF 提供了[Import]和[ImportMany]两种 attribute。 区别就是 Import 只能接受符合协议的一个扩展,而 ImportMany 可以接受多个,并把多个扩展放入集合中。6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    public partial class Form1 : Form6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    public Form1()6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    InitializeComponent();6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    [ImportMany]6ik办公区 - 实用经验教程分享!

    public IEnumerableIPlugin> plugins;6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    private void Form1_Load(object sender, EventArgs e)6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

  • 4

    提供一个符合协议的产物6ik办公区 - 实用经验教程分享!

      这个产物的生产过程其实就是实现接口的过程,唯一的区别是我们要为这个实现打上个标签,从而告诉我们的组合引擎这个东西是给接受者的。MEF 提供了 Export 来暗示这是一个可以提供给接受者的产物。6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    [Export(typeof(IPlugin))]6ik办公区 - 实用经验教程分享!

    public class MyPlugin:IPlugin6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    public string Text6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    get6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    return "This is a demo";6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    public void Do()6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    MessageBox.Show(Text);6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

  • 5

    发动引擎6ik办公区 - 实用经验教程分享!

      万事俱备,就差发动了。前面说了引擎的主要作用就是把发现扩展,同时把这些扩展组合到应用程序中。6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    private CompositionContainer _container;6ik办公区 - 实用经验教程分享!

    private void Init()6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    try6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    MyPlugin my = new MyPlugin();6ik办公区 - 实用经验教程分享!

    this._container.ComposeParts(this, my);//把扩展和实例组合在一起6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    catch (CompositionException compositionException)6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    Console.WriteLine(compositionException.ToString());6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    上面的代码虽然实现了组合的功能,但是却硬把产物给编码进去了。要是每次开发了新的扩展,都得这样修改应用程序代码,那就完全没有使用MEF的必要了,而且也违反了开放封闭的设计原则。6ik办公区 - 实用经验教程分享!

      把上面的代码改一改。6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    private CompositionContainer _container;6ik办公区 - 实用经验教程分享!

    private void Init()6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    //设置目录,让引擎能自动去发现新的扩展6ik办公区 - 实用经验教程分享!

    var catalog = new AggregateCatalog();6ik办公区 - 实用经验教程分享!

    catalog.Catalogs.Add(new DirectoryCatalog("D:plugin"));6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    //创建一个容器,相当于是生产车间6ik办公区 - 实用经验教程分享!

    _container = new CompositionContainer(catalog);6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    //调用车间的ComposeParts把各个部件组合到一起6ik办公区 - 实用经验教程分享!

    try6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    this._container.ComposeParts(this);//这里只需要传入当前应用程序实例就可以了,其它部分会自动发现并组装6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    catch (CompositionException compositionException)6ik办公区 - 实用经验教程分享!

    {6ik办公区 - 实用经验教程分享!

    Console.WriteLine(compositionException.ToString());6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    }6ik办公区 - 实用经验教程分享!

    6ik办公区 - 实用经验教程分享!

    上面的代码会自动去发现扩展,然后加入到应用程序中来。你要做的只是把新扩展的程序集放入 D:plugin 目录中就可以了。是不是很方便呢?6ik办公区 - 实用经验教程分享!

  • 参考资源

  • 1

    http://blog.chenxu.me/post/detail?id=a7098e6b-3795-428a-858f-2121f64530cb6ik办公区 - 实用经验教程分享!

  • 以上方法由办公区教程网编辑摘抄自百度经验可供大家参考!6ik办公区 - 实用经验教程分享!


    标签: 操作系统扩展程序

    办公区 Copyright © 2016-2023 www.bgqu.net. Some Rights Reserved. 备案号:湘ICP备2020019561号