编写一个插件系统需要考虑以下几个方面:
插件接口:定义插件系统的接口,即插件需要实现的功能和规范。这包括插件的输入、输出和处理方式等。
插件注册:在系统中注册插件的方式和方法。通常可以通过配置文件、代码注入或特定机制进行插件注册。
插件加载:在系统启动或需要使用插件时,加载和实例化插件的方式和方法。
插件通信:实现插件之间的通信和数据交换,包括插件之间的依赖关系、事件通知等。
插件管理:对已加载的插件进行管理,包括插件的启用、禁用、更新和卸载等操作。
下面是勇哥的一个小演示,除了插件通信外,其它的都有演示:
例子是两数计算的小程序,其中+-*/等算法是通过磁盘上的dll文件载入的。
这是调用者代码:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace CalculatorPlugin { class Program { static void Main(string[] args) { PluginLoader loader = new PluginLoader(); if (!loader.RegisterCalculator("CalculatorPluginAdd.dll")) { // 注册插件A Console.WriteLine("注册失败"); } //loader.RegisterCalculator("CalculatorPluginSub.dll"); // 注册插件B var result = loader.Calculate(2, 3); Console.WriteLine(result); var s1 = loader.GetPlugList(); Console.ReadKey(); } } public class PluginLoader { private List<ICalculator> calculators = new List<ICalculator>(); private Assembly assembly = null; public List<ICalculator> GetPlugList() { return this.calculators; } public bool RegisterCalculator(string dllPath) { try { assembly = Assembly.LoadFrom(dllPath); } catch (FileNotFoundException ex) { Console.WriteLine("文件未找到,加载程序集失败"); return false; } catch (BadImageFormatException ex) { Console.WriteLine("程序集文件格式错误,加载程序集失败"); return false; } catch (Exception ex) { Console.WriteLine("其他异常,加载程序集失败"); return false; } var s1 = assembly.GetExportedTypes(); foreach (Type type in assembly.GetExportedTypes()) { if (type.BaseType.IsAssignableFrom(typeof(ICalculator))) { ICalculator calculator = (ICalculator)Activator.CreateInstance(type); calculators.Add(calculator); } } } public void UnregisterCalculator(string dllPath) { assembly = Assembly.LoadFrom(dllPath); foreach (Type type in assembly.GetExportedTypes()) { if (type.BaseType.IsAssignableFrom(typeof(ICalculator))) { calculators.Remove(type as ICalculator); } } } public int Calculate(int a, int b) { foreach (var calculator in calculators) { try { return calculator.Cal(a, b); } catch (Exception ex) { Console.WriteLine("Error loading plugin: " + ex.Message); } } return 0; // 如果没有找到任何插件,返回0作为默认值 } } }
下面是接口ICalculator的源码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CalculatorPlugin { public interface ICalculator { int Cal(int a, int b); } }
下面是加法的算法类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CalculatorPlugin { public class CalculatorPluginAdd : ICalculator { public int Cal(int a, int b) { return a + b; } } }
下面是减法的算法类:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CalculatorPlugin { public class CalculatorPluginSub : ICalculator { public int Cal(int a, int b) { return a - b; } } }
由于用到反射,所以命名空间很重要,读者可能未必能成功测试。
我放个源码包,方便大家测试成功。
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!
下载:

