记得在学校的时候, 老师为了开拓我们的眼界, 给我们上了一堂有关反射的用法,随后给我们现场演示了一个宿主插件的例子. 虽然后来我没有在实际的项目中用到这个知识点,但是我觉得这个是一个不错的东西.
自己定义一个宿主,然后对外提供接口, 大家按照统一的接口规范来,这样就能大家一起开发,完善该插件.
我这里先说一下"宿主", 宿主一般作为一个启动器,可以有一些基础的功能,也可以没有, 宿主提供统一的接口, 对外的插件实现该接口, 然后宿主通过加载dll,反编译,调用插件里面的方法,做对应的操作或者显示.
这里介绍一种 基于Winform的宿主--插件
宿主 是一个Winform页面, 里面一个 TableControl, 每个插件 进来,就显示一个 TabPage,这样各个插件才不会冲突.
partial class Form1 { /// <summary> /// 必需的设计器变量。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 清理所有正在使用的资源。 /// </summary> /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows 窗体设计器生成的代码 /// <summary> /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容。 /// </summary> private void InitializeComponent() { this.tbcontr = new System.Windows.Forms.TabControl(); this.SuspendLayout(); // // tbcontr // this.tbcontr.Location = new System.Drawing.Point(12, 12); this.tbcontr.Name = "tbcontr"; this.tbcontr.SelectedIndex = 0; this.tbcontr.Size = new System.Drawing.Size(437, 269); this.tbcontr.TabIndex = 0; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(461, 303); this.Controls.Add(this.tbcontr); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); this.ResumeLayout(false); } #endregion private System.Windows.Forms.TabControl tbcontr; }
插件接口: 一个控件,一个文本
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; namespace plusInterfaces { public interface plusUI { Control GetUI(); string Ttitle { get; } } }
插件(单独的一个DLL): 继承插件接口,并且实现插件的方法, 完成后, 将编译后的dll文件, 拷贝到宿主运行的 plus目录下.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using plusInterfaces; using System.Windows.Forms; namespace Plus { public class Plc1 : plusUI { public Control GetUI() { Label l = new Label(); l.Text = "这是一个Lable标签"; return l; } public string Ttitle { get { return "这里显示TapPage的标题"; } } } }
再说说宿主如何加载插件.
在宿主页面的PageLoad 事件里面, 读取插件 dll,然后进行反射,然后执行 实现接口的方法和属性
private void Form1_Load(object sender, EventArgs e) { //启动时,动态加载插件 string appPath = Application.ExecutablePath;//运行的路径 string plusPath = appPath.Substring(0,appPath.LastIndexOf(@"\"))+@"\plus"; string[] plusFileNames = Directory.GetFiles(plusPath,"*.dll"); //解析 dll 看其是否实现了chajian接口 foreach (string filename in plusFileNames) { Assembly ass = Assembly.LoadFile(filename); Type[] types = ass.GetTypes(); foreach (Type type in types) { //判断type是否是插件 Type[] interFacesType = type.GetInterfaces(); foreach (Type typeInterface in interFacesType) { if (typeInterface.FullName=="plusInterfaces.plusUI") { //实现该类的接口,就是插件 plusUI plus = (plusUI)Activator.CreateInstance(type); Control control = plus.GetUI(); control.Dock = DockStyle.Fill; TabPage page = new TabPage(); page.Text = plus.Ttitle; page.Controls.Add(control); this.tbcontr.TabPages.Add(page); } } } } }
现在直接运行宿主, 就能加载插件了.
示例下载: WinHostPlus