C#反射实现插件式开发

这篇具有很好参考价值的文章主要介绍了C#反射实现插件式开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

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

项目介绍

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

目标框架:.NET Framework 4.6.1

项目架构和窗体布局:

C#反射实现插件式开发

客户端程序:

  • 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文件夹下。

C#反射实现插件式开发

插件路径配置

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

C#反射实现插件式开发

插件基类配置

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

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

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

C#反射实现插件式开发

调用演示

CustomPlugInA

C#反射实现插件式开发

CustomPlugInB

C#反射实现插件式开发

CustomPlugInC

C#反射实现插件式开发

CustomPlugInD

C#反射实现插件式开发

插件开发优缺点

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

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

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

源码获取

关注公众号,后台回复关键字:Plugin文章来源地址https://www.toymoban.com/news/detail-709829.html

到了这里,关于C#反射实现插件式开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【创建型设计模式】C#设计模式之工厂模式,以及通过反射实现动态工厂。

    题目如下: 简单工厂实现: 上述代码给出了抽象基类的基本定义,和泛型工厂的实现方式,以及调用方式。 值得注意的是 where T : Car, new() 这个条件: where T : Car, new() 是对泛型类型参数 T 的约束。这个约束表明泛型类型参数 T 必须满足两个条件: T 必须是 Car 类或者其派生类

    2024年02月11日
    浏览(43)
  • 从零开始理解Linux中断架构(1)-前言

    前言         前段时间在转行手撸WIFI路由器,搞wifi路由器需要理解网络驱动程序,以太网卡驱动程序,无线WIFI驱动程序,而网卡驱动的关键路径就在中断程序中,需要了解NIC设备驱动程序如何收发数据,为了彻底的知道数据包是如何二层传递上来的,又需要了解一点Lin

    2024年02月09日
    浏览(56)
  • C#插件式开发——详解程序集Assemblies

    Assembly是.net中的基本部署单元,也是所有类型的容器。程序集包含编译类型及其 IL(中间语言)代码、运行时资源和信息,以助于版本控制、安全和引用其他程序集。程序集定义了类型解析和安全许可的边界。 一般来说,一个程序集包括一个单一的Windows可移植执行文件(P

    2024年02月04日
    浏览(38)
  • ArcGis Pro如何通过C#进行插件开发?

      ArcGIS Pro插件(Add-ins)可以让用户更加容易的自定义和扩展ArcGIS Pro应用程序,它创建一系列自定义工具提供了一个公开的基础框架,打包压缩成了一个单独的文件。 Add-ins插件能够很方便的在用户之间共享,因为它们既不需要安装程序 ,也不需要组件模型(COM)注册。本

    2024年02月12日
    浏览(111)
  • C# SolidWorks 二次开发 -从零开始创建一个插件(2)

    上一篇我详细讲解了如何创建一个插件,但是无界面无按钮,这种插件适合配合事件偷偷的在后台做点什么事情。今天这篇讲一下如何增加一些按钮到工具栏、菜单上去。 先告诉大家这个东西注册表在哪,因为solidworks在这方面做的不太好,插件你改个名字,就有多个工具栏

    2024年02月15日
    浏览(60)
  • 【C#进阶】C# 反射

    序号 系列文章 11 【C#基础】C# 预处理器指令 12 【C#基础】C# 文件与IO 13 【C#进阶】C# 特性 ✋ 大家好,我是writer桑,本章为大家介绍 C# 中的 反射 。 反射 指的是程序可以 访问,检测和修改 它本身状态或行为的一种行为。 其中访问的目标包括程序集 1 、模块和类型对象等。可

    2024年03月15日
    浏览(49)
  • 中创|通用区块链为libp2p开发人员引入插件架构

    Koinos已经被称为第一个真正免费使用的通用区块链,但你知道它也是第一批建立在微服务架构上的区块链之一吗?通过将区块链节点分解为一组松散耦合的服务, Koinos变得可维护和易于验证,同时提供了很大程度的部署灵活性 。 在该微服务架构中存在一个主要依赖于 libp2

    2024年01月20日
    浏览(47)
  • C#反射的学习,反射的一些注意事项,反射的一些使用代码的实例

    本文档写的的是C#中的反射常用的方式(附带示例代码)以及在使用的时候的一些注意事项。 C#中的反射是一种强大的机制,它允许在运行时动态地检查、访问和操作程序的元数据、类型信息和对象。以下是C#中反射常用的技巧和使用方式: 获取类型信息:使用Type类可以获取

    2024年02月06日
    浏览(54)
  • C#基础--反射

    因为反射真的是无处不在,ORM、MVC、IOC、AOP、Attribute等等都会使用到反射。反射是程序员的快乐 Ilspy:逆向工程,可以吧DLL/Exe文件反编译回来 DLL/EXE 文件下包含Metadata和IL,IL是对标于C#代码的代码,属于中间语言,是标准的面向对象语言 而Metadata(元数据)是一个清单数据,

    2024年02月16日
    浏览(31)
  • C#编程-属性和反射

    属性是将元数据信息和行为添加到应用程序代码中的简单技术。属性是允许您将声明信息添加到程序的元素。此声明信息在运行时用途广泛,可使用应用程序开发工具在设计时使用。 对象是由其属性值描述的。例如,汽车可以使用它的构造、型号或颜色来描述。类似地,C#程

    2024年01月18日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包