前言

在 C# 中,MEF(Managed Extensibility Framework) 是 .NET 官方的插件化框架,用于构建可扩展的应用程序,典型就是插件编程,本文就来介绍如何通过Mef实现插件编程。

1、Mef核心组件

1)部件 (Part)
部件是可扩展的功能单元,主要是类,并且使用Export实现导出, Import实现导入。
2)目录 (Catalog)
目录用于发现可用部件,可以通过AggregateCatalog, DirectoryCatalog,AssemblyCatalog等获取部件。
3)容器 (Container)
组合部件并解析依赖 CompositionContainer,所谓组合是把多个部件存储到一起;所谓解析依赖对于类来说就是创建类的对象。

2、使用步骤

2.1 创建部件

2.1.1 创建接口

新建一个类库PlugInterface,并且定义一个接口IPlugin,定义一个方法Do,如下:
在这里插入图片描述

namespace PlugInterface
{
    public interface  IPlugin
    {
        void Do();
    }
}

2.1.2 创建部件1

新建一个类库Plugin1,创建部件1也就是MyPlug1类,继承IPlugin接口,并且实现接口的Do方法,最后将部件通过Export导出。
在这里插入图片描述

namespace Plugin1
{
    [Export(typeof(IPlugin))]
    public class MyPlug1:IPlugin
    {
        public void Do()
        {
            Console.WriteLine("插件1");
        }
    }
}

2.1.2 创建部件2

创建部件2也就是新建一个类MyPlug2,继承IPlugin接口,并且实现接口的Do方法,最后将部件通过Export导出。
在这里插入图片描述

namespace mefTest
{
    [Export(typeof(IPlugin))]
    class MyPlug2:IPlugin
    {
        public void Do()
        {
            Console.WriteLine("插件2");
        }
    }
}

2.1.3 创建部件3

新建一个类库Plugin3,创建部件3也就是MyPlug3类,继承IPlugin接口,并且实现接口的Do方法,最后将部件通过Export导出。
在这里插入图片描述

namespace Plugin3
{
    [Export(typeof(IPlugin))]
    public class MyPlug3:IPlugin 
    {
        public void Do()
        {
            Console.WriteLine("插件3");
        }
    }
}

至此三个部件MyPlug1、MyPlug2、MyPlug3都创建好了,这里需要注意的是MyPlug1和MyPlug3是在单独的类库中创建;MyPlug2是直接在MefTest程序集,所以说这三个部件是处于不同的程序集,MyPlug1的命名空间是Plugin1,所以程序集就是Plugin1;MyPlug2的命名空间是mefTest,所以程序集就是mefTest;MyPlug3的命名空间是Plugin3,所以程序集就是Plugin3;不同的程序集意味着组合部件的时候使用方法是不同的。

2.2 组合部件

我们在Form1窗体类中定义一个方法Initial用于组合部件,代码如下:



namespace mefTest
{
    public partial class Form1 : Form
    {
        private string ApplicationPath= Environment.CurrentDirectory + "\\lib\\";
        public Form1()
        {
            InitializeComponent();
            Initial();
        }


        private void Initial()
        {
            var mainCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var pluginCatalog = new AssemblyCatalog(Assembly.LoadFrom("Plugin1.dll"));
            DirectoryCatalog catalog = new DirectoryCatalog(ApplicationPath);
            // 组合多个目录
            var aggregateCatalog = new AggregateCatalog(mainCatalog, pluginCatalog);
            aggregateCatalog.Catalogs.Add(catalog);
            // 4. 创建容器
            var container = new CompositionContainer(aggregateCatalog);
            var plugin = container.GetExportedValues<IPlugin>();
            foreach (var item in plugin)
            {
                item.Do();
            }
        }
    }
}

2.2.1 Assembly.GetExecutingAssembly()

该方法用于获取当前执行的程序集,由于当前执行程序集是mefTest,而mefTest程序集中只有部件2也就是MyPlug2,所以通过var mainCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());能获取到MyPlug2部件。

2.2.2 Assembly.LoadFrom(“Plugin1.dll”)

Assembly.LoadFrom方法用于根据程序集的文件名来获取程序集,我们这里将Plugin1.dll也就是部件1放到程序运行目录下,由于LoadFrom方法中没有传入绝对路径,只传入文件名,所以直接从程序运行目录下寻找Plugin1.dll,这样就能获取到MyPlug1部件.
在这里插入图片描述

2.2.3 DirectoryCatalog catalog = new DirectoryCatalog(ApplicationPath)

DirectoryCatalog用于从指定目录下加载所有程序集,这里将部件3放入运行目录下的一个lib文件夹内,然后通过 DirectoryCatalog catalog = new DirectoryCatalog(ApplicationPath);来读取,所以可将部件3加载。
在这里插入图片描述

2.2.4 组合目录

下面的代码用于将存储部件的多个不同的目录进行组合,可以直接使用构造函数传参,也可以获取AggregateCatalog的Catalogs属性的Add方法添加。

 var aggregateCatalog = new AggregateCatalog(mainCatalog, pluginCatalog);
            aggregateCatalog.Catalogs.Add(catalog);

2.2.5 创建容器

下面的代码是固定用法,将AggregateCatalog对象传入CompositionContainer类中,这样容器就负责管理多个部件

 var container = new CompositionContainer(aggregateCatalog);

2.3 导入并使用部件

下面的代码中我们调用容器的GetExportedValues方法,这样就得到了一个部件的集合,最后使用循环调用部件的Do方法,三个部件都成功被调用

var plugin = container.GetExportedValues<IPlugin>();
            foreach (var item in plugin)
            {
                item.Do();
            }

输出结果:
在这里插入图片描述

2.4 插件的插拔与替换

插件就是这里的部件的意思

2.4.1 拔掉插件

删除lib文件夹下的Plugin3.dll,再次运行程序发现插件3没有被成功加载。
在这里插入图片描述

2.4.1 替换插件

将Plugin1.dll放入lib文件夹下,再次运行程序,调用了两次插件1,说明lib文件夹下的插件3被我们替换成了插件1,这样就实现了插件的拔插,这就是插件编程的原理,我们通过替换dll来实现不同的功能。
在这里插入图片描述
在这里插入图片描述

马工撰写的年入30万+C#上位机项目实战必备教程(点击下方链接即可访问文章目录)

1、《C#串口通信从入门到精通》
2、《C#与PLC通信从入门到精通 》
3、《C# Modbus通信从入门到精通》
4、《C#Socket通信从入门到精通 》
5、《C# MES通信从入门到精通》
6、《winform控件从入门到精通》
7、《C#操作MySql数据库从入门到精通》

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐