• C#反射实现插件式开发


    前言

    插件式架构,一种全新的、开放性的、高扩展性的架构体系。插件式架构设计好处很多,把扩展功能从框架中剥离出来,降低了框架的复杂度,让框架更容易实现。扩展功能与框架以一种很松的方式耦合,两者在保持接口不变的情况下,可以独立变化和发布。基于插件设计并不神秘,相反它比起一团泥的设计更简单,更容易理解。

    项目介绍

    书写4个插件类库,分别传参实现“加减乘除”运算,调用插件的客户端采用Winform窗体程序。

    目标框架:.NET Framework 4.6.1

    项目架构和窗体布局:

    image

    客户端程序:

    • PluginApp:反射调用插件

    插件描述:

    • PluginBase:规范插件的基类,定义抽象类,开发的插件的类需要继承此类,代表遵守这个规范。
    • CustomPlugInA:实现加法的插件
    • CustomPlugInB:实现减法的插件
    • CustomPlugInC:实现乘法的插件
    • CustomPlugInD:实现除法的插件

    代码实现

    插件基类
     /// 
        ///插件基类
        /// 
        public abstract class Base
        {
            /// 
            /// 插件名称
            /// 
            /// 
            public abstract string Name();
           /// 
           /// 插件描述
           /// 
           /// 
            public abstract string Desc();
            /// 
            /// 执行方法
            /// 
            /// 参数1
            /// 参数2
            /// 
            public abstract string Run(int param1, int param2);
            /// 
            /// 版本 
            /// 
            public string Version
            {
                get { return "1.0.0"; }
            }
        }
    
    PlugInA
        public class PlugInA: Base
        {
    
            public override string Name()
            {
                return "PlugInA";
            }
    
            public override string Desc()
            {
                return "加法";
            }
    
            public override string Run(int param1,int param2)
            {
                return (param1 + param2) + "";
            }
        }
    }
    
    PlugInB
        public class PlugInB : Base
        {
    
            public override string Name()
            {
                return "PlugInB";
            }
    
            public override string Desc()
            {
                return "减法";
            }
    
            public override string Run(int param1, int param2)
            {
                return (param1 - param2) + "";
            }
        }
    
    PlugInC
      public class PlugInC : Base
        {
    
            public override string Name()
            {
                return "PlugInC";
            }
    
            public override string Desc()
            {
                return "乘法";
            }
    
            public override string Run(int param1, int param2)
            {
                return (param1 * param2) + "";
            }
        }
    
    PlugInD
     public class PlugInD : Base
        {
    
            public override string Name()
            {
                return "PlugInD";
            }
    
            public override string Desc()
            {
                return "除法";
            }
    
            public override string Run(int param1, int param2)
            {
                return (param1 / param2) + "";
            }
        }
    
    客户端核心代码:
       public partial class FrmMain : Form
        {
            public FrmMain()
            {
                InitializeComponent();
                dgrvPlugins.AutoGenerateColumns = false;
            }
    
            List List = new List();
    
            readonly string PlugInPath = Application.StartupPath + "\\PlugIns";
    
            /// 
            /// 载入插件
            /// 
            /// 
            /// 
            private void btLoadPlugins_Click(object sender, EventArgs e)
            {
    
                if (!Directory.Exists(PlugInPath))
                {
                    Directory.CreateDirectory(PlugInPath);
                }
                List.Clear();
                string[] files = Directory.GetFiles(PlugInPath);
                foreach (string file in files)
                {
                    if (file.ToLower().EndsWith(".dll"))
                    {
                        try
                        {
                            Assembly assembly = Assembly.LoadFrom(file);
                            Type[] types = assembly.GetTypes();
                            foreach (Type type in types)
                            {
                                if (type.BaseType.FullName == "PlugInBase.Base")
                                {
                                    object obj = assembly.CreateInstance(type.FullName);
                                    string name = type.GetMethod("Name").Invoke(obj, null).ToString();
                                    string desc = type.GetMethod("Desc").Invoke(obj, null).ToString();
                                    string version = type.GetProperty("Version").GetValue(obj).ToString();
    
                                    List.Add(new PluginModel
                                    {
                                        Name = name,
                                        Desc = desc,
                                        Version = version,
                                        type = type,
                                        Obj = obj
                                    });
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }
                }
    
                dgrvPlugins.DataSource = new BindingList(List);
            }
    
            /// 
            /// 打开插件目录
            /// 
            /// 
            /// 
            private void btOpenPluginDir_Click(object sender, EventArgs e)
            {
                Process.Start(PlugInPath);
            }
    
    
            /// 
            /// 执行选中插件
            /// 
            /// 
            /// 
            private void btExcute_Click(object sender, EventArgs e)
            {
                //获取选择的插件信息
                int index = dgrvPlugins.CurrentRow.Index;
                object obj = List[index].Obj;
                Type type = List[index].type;
                //参数
                object[] inParams = new object[2];
                inParams[0] =Convert.ToInt32( dgrvPlugins.CurrentRow.Cells[2].Value);
                inParams[1] = Convert.ToInt32(dgrvPlugins.CurrentRow.Cells[3].Value);
                object value = type.GetMethod("Run").Invoke(obj, inParams);
                MessageBox.Show(Convert.ToString(value),"结果",MessageBoxButtons.OK);
            }
        }
    

    项目配置

    插件生成配置

    编译生成项目的时候需要注意,此处的调用插件是通过反射调用.dll中类和方法,所以首先要找到这个.dll的文件,所以此处我们在Winform客户端程序下建立一个存放类库dll的文件PlugIns,在插件类库项目生成后事件命令中,填入如下命令:

    copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\PlugIns"
    

    以上命令代表,在项目的类库生成后,将类库copy到解决方案的路径子文件夹PlugIns,也就是我们建立存放自定义插件的文件夹。当然,如果不怕麻烦,每次生成后,手动复制到此文件夹也可以,直接复制到客户端程序的..\bin\PlugIns文件夹下。

    image

    插件路径配置

    全选这些类库,把这些类库设置为"如果较新则复制",这样每次在编译客户端程序,如果自定义插件有更新,则同步会复制到bin目录下

    image

    插件基类配置

    插件基类提供了规范,需要在类库的生成后事件,添加命令:

    copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\bin\Debug"
    

    将生成的dll文件,拷贝到客户端程序的bin路径下

    image

    调用演示

    CustomPlugInA

    image

    CustomPlugInB

    image

    CustomPlugInC

    image

    CustomPlugInD

    image

    插件开发优缺点

    优点
    • 把扩展功能从框架中剥离出来,降低了框架的复杂度,让框架更容易实现
    • 宿主中可以对各个模块解析,完成插件间、插件和主程序间的通信。
    • 插件开发的可扩展性,灵活性比较高,而且可以进行定制化开发。
    缺点
    • 每一个插件被编译成了dll,各模块无法单独运行,必须依托于主程序。

    • 修改插件时,由于生成的是dll,无法快速直观的查看修改以及调试。

    • 每一个插件必须依赖于某一个规范。

    源码获取

    关注公众号,后台回复关键字:Plugin

  • 相关阅读:
    mongodb、mysql、redis 区别
    PMI新人才三角如何构建自己的影响力?【洞见1】
    如何删除kafka主题数据
    菜品识别易语言代码
    Spring中如何获取JavaBean呢?
    ROS1云课→30导航仿真演示
    Ajax与jQuery
    重建与发展:数字资产借贷行业朝着可持续发展迈进!
    一款好用的PDF转翻页电子书网站
    2024.06.11校招 实习 内推 面经
  • 原文地址:https://www.cnblogs.com/wml-it/p/17706182.html