首页 > 其他分享 >反射实现插件式开发

反射实现插件式开发

时间:2023-09-15 23:55:29浏览次数:32  
标签:反射 插件 return string 开发 override type public

前言

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

项目介绍

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

目标框架:.NET Framework 4.6.1

项目架构和窗体布局:

image

客户端程序:

  • PluginApp:反射调用插件

插件描述:

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

代码实现

插件基类
 /// <summary>
    ///插件基类
    /// </summary>
    public abstract class Base
    {
        /// <summary>
        /// 插件名称
        /// </summary>
        /// <returns></returns>
        public abstract string Name();
       /// <summary>
       /// 插件描述
       /// </summary>
       /// <returns></returns>
        public abstract string Desc();
        /// <summary>
        /// 执行方法
        /// </summary>
        /// <param name="param1">参数1</param>
        /// <param name="param2">参数2</param>
        /// <returns></returns>
        public abstract string Run(int param1, int param2);
        /// <summary>
        /// 版本 
        /// </summary>
        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<PluginModel> List = new List<PluginModel>();

        readonly string PlugInPath = Application.StartupPath + "\\PlugIns";

        /// <summary>
        /// 载入插件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        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<PluginModel>(List);
        }

        /// <summary>
        /// 打开插件目录
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btOpenPluginDir_Click(object sender, EventArgs e)
        {
            Process.Start(PlugInPath);
        }


        /// <summary>
        /// 执行选中插件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        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,无法快速直观的查看修改以及调试。

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

标签:反射,插件,return,string,开发,override,type,public
From: https://www.cnblogs.com/wml-it/p/17706182.html

相关文章

  • python开发商品扫描录入模型
       最近市场监管部门加大了对销售过期商品的处罚力度。很多菜店、粮店等店不大但商品品种、货号批次却非常多。这里介绍两个可以用手机扫描录入商品数据的模型,供大家二次开发,设计出一个管理商品失效日期的小程序。   模型一importsqlite3frompyzbar.pyzbarimport......
  • 3.反射
    JAVA反射机制:是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制。一个反射解析器:运用泛型、反射、集合类等相关知识实现一个API参数解析器......
  • 快速分析项目状况!试试这款项目代码统计 IDEA 插件—— Statistic
    前言InteIIiJIDEA2023.2版本发布了,在2023.2中,官方根据用户的宝贵反馈对新UI做出了大量改进,新UI界面大大减少了干扰,可以让用户更好地专注于代码。但官方激活码的校验规则进行了更新,之前已经成功激活的Idea可能突然无法使用了,给大家准备了激活码:IDEA激活 https://www.kdocs.c......
  • ​​老板要我开发一个简单的工作流引擎​​​-读后感与补充​
    概述最近读了一篇《老板要我开发一个简单的工作流引擎》幽默风趣,干货较多,作为流程引擎的设计者、开发者、探索者,写的很好,合计自己的理解,对每个功能补充说明,对于流程引擎的应用场景,做出更好的理解与实践。第1关-线性流程一天,老板找到我,说要做个简单的工作流引擎。我查了一天啥是工......
  • 从腾讯云开发迁移到 Laf 完全指南!
    laf背景概述目前,我的小程序运行在腾讯云Cloudbase平台上,采用基础套餐+按量付费的计费方式。虽然每月费用大约在100元左右,但我认为这是不必要的。此前由于时间紧迫,我并未对腾讯云的优惠政策进行深入了解。在与@白夜讨论了计费规则后,我对收费机制有了更清晰的认识。另外,由于对@......
  • 推荐一款IDEA插件,帮你快速统计「烂代码」
    Statistic插件编程是一个很奇妙的事情,大部分的我们把大部分时间实际都花在了复制粘贴,而后修改代码上面。很多时候,我们并不关注代码质量,只要功能能实现,我才不管一个类的代码有多长、一个方法的代码有多长。因此,我们经常会碰到让自己想要骂街的项目,不过,说真的,你自己写的代码也有......
  • 跨平台的PHP开发IDE-PhpStorm 2023 mac+win版
    PhpStorm2023是一款专门为PHP开发人员设计的集成开发环境(IDE)。→→↓↓载PhpStorm2023mac/win它提供了丰富的功能,包括代码编辑、调试、版本控制、自动完成、代码检查、测试等,可以帮助开发人员更高效地编写和维护PHP代码。此外,它还支持多种框架,包括Symfony、Laravel、Yii、Zen......
  • Python集成开发环境IDE-Pycharm 2023 win+mac版
    PyCharm2023是一种流行的集成开发环境(IDE),专门为Python开发人员设计.→→↓↓载Pycharm2023mac/winPyCharm2023版提供了强大的代码编辑器,支持智能代码完成、代码分析、代码重构等功能。它还可以自动检测错误并提供修复建议。PyCharm的调试器非常强大,可以帮助开发人员诊断和......
  • 第二十章 反射机制
    20.1基本概念通常情况下编写代码都是固定的,无论运行多少次执行的结果也是固定的,在某些特殊场合中编写代码时不确定要创建什么类型的对象,也不确定要调用什么样的方法,这些都希望通过运行时传递的参数来决定,该机制叫做动态编程技术,也就是反射机制。通俗来说,反射机制就是用于动......
  • 反写规则引入到应用(协同开发云)
     创建反写规则可以看:金蝶云星空反写规则的使用-lanrenka-博客园(cnblogs.com) 具体操作:1、打开应用——供应链——预置数据——反写规则预置数据 2、右键【反写规则预置数据】——引入反写规则  3、选择需要引入的反写规则,如果是全部可以选择顶部进行全选 4......