编写一个插件系统需要考虑以下几个方面:
插件接口:定义插件系统的接口,即插件需要实现的功能和规范。这包括插件的输入、输出和处理方式等。
插件注册:在系统中注册插件的方式和方法。通常可以通过配置文件、代码注入或特定机制进行插件注册。
插件加载:在系统启动或需要使用插件时,加载和实例化插件的方式和方法。
插件通信:实现插件之间的通信和数据交换,包括插件之间的依赖关系、事件通知等。
插件管理:对已加载的插件进行管理,包括插件的启用、禁用、更新和卸载等操作。
下面是勇哥的一个小演示,除了插件通信外,其它的都有演示:
例子是两数计算的小程序,其中+-*/等算法是通过磁盘上的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
版权声明:本文为博主原创文章,转载请附上博文链接!
下载: