翼度科技»论坛 编程开发 .net 查看内容

C#反射实现插件式开发

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
前言

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

书写4个插件类库,分别传参实现“加减乘除”运算,调用插件的客户端采用Winform窗体程序。
目标框架:.NET Framework 4.6.1
项目架构和窗体布局:

客户端程序:

  • PluginApp:反射调用插件
插件描述:

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

插件基类
  1. /// <summary>
  2.     ///插件基类
  3.     /// </summary>
  4.     public abstract class Base
  5.     {
  6.         /// <summary>
  7.         /// 插件名称
  8.         /// </summary>
  9.         /// <returns></returns>
  10.         public abstract string Name();
  11.        /// <summary>
  12.        /// 插件描述
  13.        /// </summary>
  14.        /// <returns></returns>
  15.         public abstract string Desc();
  16.         /// <summary>
  17.         /// 执行方法
  18.         /// </summary>
  19.         /// <param name="param1">参数1</param>
  20.         /// <param name="param2">参数2</param>
  21.         /// <returns></returns>
  22.         public abstract string Run(int param1, int param2);
  23.         /// <summary>
  24.         /// 版本
  25.         /// </summary>
  26.         public string Version
  27.         {
  28.             get { return "1.0.0"; }
  29.         }
  30.     }
复制代码
PlugInA
  1.     public class PlugInA: Base
  2.     {
  3.         public override string Name()
  4.         {
  5.             return "PlugInA";
  6.         }
  7.         public override string Desc()
  8.         {
  9.             return "加法";
  10.         }
  11.         public override string Run(int param1,int param2)
  12.         {
  13.             return (param1 + param2) + "";
  14.         }
  15.     }
  16. }
复制代码
PlugInB
  1.     public class PlugInB : Base
  2.     {
  3.         public override string Name()
  4.         {
  5.             return "PlugInB";
  6.         }
  7.         public override string Desc()
  8.         {
  9.             return "减法";
  10.         }
  11.         public override string Run(int param1, int param2)
  12.         {
  13.             return (param1 - param2) + "";
  14.         }
  15.     }
复制代码
PlugInC
  1.   public class PlugInC : Base
  2.     {
  3.         public override string Name()
  4.         {
  5.             return "PlugInC";
  6.         }
  7.         public override string Desc()
  8.         {
  9.             return "乘法";
  10.         }
  11.         public override string Run(int param1, int param2)
  12.         {
  13.             return (param1 * param2) + "";
  14.         }
  15.     }
复制代码
PlugInD
  1. public class PlugInD : Base
  2.     {
  3.         public override string Name()
  4.         {
  5.             return "PlugInD";
  6.         }
  7.         public override string Desc()
  8.         {
  9.             return "除法";
  10.         }
  11.         public override string Run(int param1, int param2)
  12.         {
  13.             return (param1 / param2) + "";
  14.         }
  15.     }
复制代码
客户端核心代码:
  1.    public partial class FrmMain : Form
  2.     {
  3.         public FrmMain()
  4.         {
  5.             InitializeComponent();
  6.             dgrvPlugins.AutoGenerateColumns = false;
  7.         }
  8.         List<PluginModel> List = new List<PluginModel>();
  9.         readonly string PlugInPath = Application.StartupPath + "\\PlugIns";
  10.         /// <summary>
  11.         /// 载入插件
  12.         /// </summary>
  13.         /// <param name="sender"></param>
  14.         /// <param name="e"></param>
  15.         private void btLoadPlugins_Click(object sender, EventArgs e)
  16.         {
  17.             if (!Directory.Exists(PlugInPath))
  18.             {
  19.                 Directory.CreateDirectory(PlugInPath);
  20.             }
  21.             List.Clear();
  22.             string[] files = Directory.GetFiles(PlugInPath);
  23.             foreach (string file in files)
  24.             {
  25.                 if (file.ToLower().EndsWith(".dll"))
  26.                 {
  27.                     try
  28.                     {
  29.                         Assembly assembly = Assembly.LoadFrom(file);
  30.                         Type[] types = assembly.GetTypes();
  31.                         foreach (Type type in types)
  32.                         {
  33.                             if (type.BaseType.FullName == "PlugInBase.Base")
  34.                             {
  35.                                 object obj = assembly.CreateInstance(type.FullName);
  36.                                 string name = type.GetMethod("Name").Invoke(obj, null).ToString();
  37.                                 string desc = type.GetMethod("Desc").Invoke(obj, null).ToString();
  38.                                 string version = type.GetProperty("Version").GetValue(obj).ToString();
  39.                                 List.Add(new PluginModel
  40.                                 {
  41.                                     Name = name,
  42.                                     Desc = desc,
  43.                                     Version = version,
  44.                                     type = type,
  45.                                     Obj = obj
  46.                                 });
  47.                             }
  48.                         }
  49.                     }
  50.                     catch (Exception ex)
  51.                     {
  52.                         throw ex;
  53.                     }
  54.                 }
  55.             }
  56.             dgrvPlugins.DataSource = new BindingList<PluginModel>(List);
  57.         }
  58.         /// <summary>
  59.         /// 打开插件目录
  60.         /// </summary>
  61.         /// <param name="sender"></param>
  62.         /// <param name="e"></param>
  63.         private void btOpenPluginDir_Click(object sender, EventArgs e)
  64.         {
  65.             Process.Start(PlugInPath);
  66.         }
  67.         /// <summary>
  68.         /// 执行选中插件
  69.         /// </summary>
  70.         /// <param name="sender"></param>
  71.         /// <param name="e"></param>
  72.         private void btExcute_Click(object sender, EventArgs e)
  73.         {
  74.             //获取选择的插件信息
  75.             int index = dgrvPlugins.CurrentRow.Index;
  76.             object obj = List[index].Obj;
  77.             Type type = List[index].type;
  78.             //参数
  79.             object[] inParams = new object[2];
  80.             inParams[0] =Convert.ToInt32( dgrvPlugins.CurrentRow.Cells[2].Value);
  81.             inParams[1] = Convert.ToInt32(dgrvPlugins.CurrentRow.Cells[3].Value);
  82.             object value = type.GetMethod("Run").Invoke(obj, inParams);
  83.             MessageBox.Show(Convert.ToString(value),"结果",MessageBoxButtons.OK);
  84.         }
  85.     }
复制代码
项目配置

插件生成配置

编译生成项目的时候需要注意,此处的调用插件是通过反射调用.dll中类和方法,所以首先要找到这个.dll的文件,所以此处我们在Winform客户端程序下建立一个存放类库dll的文件PlugIns,在插件类库项目生成后事件命令中,填入如下命令:
  1. copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\PlugIns"
复制代码
以上命令代表,在项目的类库生成后,将类库copy到解决方案的路径子文件夹PlugIns,也就是我们建立存放自定义插件的文件夹。当然,如果不怕麻烦,每次生成后,手动复制到此文件夹也可以,直接复制到客户端程序的..\bin\PlugIns文件夹下。

插件路径配置

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

插件基类配置

插件基类提供了规范,需要在类库的生成后事件,添加命令:
  1. copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\bin\Debug"
复制代码
将生成的dll文件,拷贝到客户端程序的bin路径下

调用演示

CustomPlugInA


CustomPlugInB


CustomPlugInC


CustomPlugInD


插件开发优缺点


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


  • 每一个插件被编译成了dll,各模块无法单独运行,必须依托于主程序。
  • 修改插件时,由于生成的是dll,无法快速直观的查看修改以及调试。
  • 每一个插件必须依赖于某一个规范。

来源:https://www.cnblogs.com/wml-it/archive/2023/09/15/17706182.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具