C#插件编程(基础)
程序界面运行如下:
//==============================================================
首先,我们要定义一个插件接口,接口规范了插件内部类的程序结构,应实现的字段,属性,方法,事件。
using System; using System.Collections.Generic; using System.Text;
namespace IMsg { //这是插件必须要实现的接口,也是主程序与插件通信的唯一接口, //换句话说,主程序只认识插件里的这些方法 public interface IMsgPlug { void OnShowDlg(); string OnShowInfo(); } }
再者,需要实现接口在主程序内部的处理过程,包括载入插件,获取插件内部的被接口规范了的字段,属性,方法,事件。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Reflection; using System.Collections; using IMsg;
namespace MsgBoxMain { public partial class FormMain : Form { public ArrayList plugins = new ArrayList(); public FormMain() { InitializeComponent(); } //载入插件 private void LoadAllPlugins() { //获取指定插件目录下的所有文件的文件名 string[] files = Directory.GetFiles(Application.StartupPath + @"\plugins"); //遍历该文件名集合 foreach (string file in files) { //检索出文件名以.dll结束的文件 if (file.Substring(file.LastIndexOf(".")) == ".dll") { try { //载入dll Assembly ab = Assembly.LoadFile(file); //获得载入的dll中的所有类 Type[] tempTs = ab.GetTypes(); //遍历该类集合 foreach (Type tp in tempTs) { //如果某些类实现了预定义的IMsg.IMsgPlug接口,则认为该类适配与主程序(是主程序的插件) if (IsValidPlugin(tp)) { //实例化该类,并将对象装入动态数组plugins plugins.Add(ab.CreateInstance(tp.FullName)); //将该类型名载入列表框内 ListItems.Items.Add(tp.Name.ToString()); } } } catch(Exception ex) { MessageBox.Show(ex.ToString(), "加载插件出错", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } //判断模块的类是否满足预定义接口 private bool IsValidPlugin(Type t) { bool ret = false; Type[] interfaces = t.GetInterfaces(); foreach (Type theInterface in interfaces) { if (theInterface.FullName == "IMsg.IMsgPlug") { ret = true; break; } } return ret; } //调用插件内的方法 private void button2_Click(object sender, EventArgs e) {
//获取列表框内被选择的项 string itemStr = ListItems.SelectedItem.ToString(); if(ListItems.SelectedIndex >= 0) { if (itemStr == "myConsole") { //调用存储在动态数组plugins里面的插件对象的OnShowInfo方法 string msgInfo = ((IMsgPlug)plugins[ListItems.SelectedIndex]).OnShowInfo(); MessageBox.Show(msgInfo, "MYPlugin1", MessageBoxButtons.OK, MessageBoxIcon.Information); } else if (itemStr == "MYDlg")//调用存储在动态数组plugins里面的插件对象的OnShowDlg方法 { ((IMsgPlug)plugins[ListItems.SelectedIndex]).OnShowDlg(); } } else MessageBox.Show("请先选择列表框里的插件项", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); }
private void button1_Click(object sender, EventArgs e) { try { //载入插件 LoadAllPlugins(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } } } }
最后,编写插件类库,实现接口的属性,方法,事件。
//程序集(dll)内部的一个类1,该类实现了插件接口
using System; using System.Collections.Generic; using System.Text; using IMsg;
namespace MYPlugin1 { //实现插件接口 public class myConsole : IMsgPlug { public void OnShowDlg() {} public string OnShowInfo() { return "调用了插件1的OnShowInfo方法!"; } } }
//程序集(dll)内部的一个类2,该类实现了也插件接口
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using IMsg;
namespace MYPlugin1 { //实现插件接口 public partial class MYDlg : Form, IMsgPlug { public MYDlg() { InitializeComponent(); }
//============================================= public string OnShowInfo() { return null; } public void OnShowDlg() { this.Show(); } //============================================= } }
总结: 通过反射以及接口使C#下的插件编程变得容易,我们在接口中定义的字段,属性,方法,事件是在插件里面被实现的,是在主程序里被解析的。主程序通过公共的接口访问插件