C# 插件式程序开发

什么是插件式编程

  提起插件式,我们首先想到的是firefox, 用过firefox的人都知道它是一个插件式程序。当一个功能需要,完全可以从网上下载一个插件后,重启后,就能使用。这个功能给我们带来许多的方便之处,这就是插件式程序的好处。

  插件的本质在于不修改程序主体(平台)的情况下对软件功能进行拓展与加强,当插件的接口公开后,任何公司或个人都可以制作自己的插件来解决一些操作上的不便或增加新功能,也就是真正意义上实现“即插即用”软件开发。

  平台+插件软件结构是将一个待开发的目标软件分为两部分,一部分为软件的主体或框架,可定义为平台,这是预先编译后的程序。另一部分为功能或补充模块,可定义为插件。这个就是后来要进行安装的插件程序。

  假设你的程序已经部署在用户的计算机上,并且能够正常运行了。但是有一天,用户打来电话——他们需要增加新的功能。确定了用户的需求后,你竟然发现原有的软件架构已经无法胜任新增任务的需求——你需要重新设计这个应用了!但问题是,就算你又用了一个开发周期完成了用户需要的应用,切不能保证用户的需求不会再次变更。也就是说,需求蔓延的可能性依然存在。因此,这种情况下插件架构更能显示出它的优越性。

  可以这么说,用它可以带来方便的地方,而且开发它,也很简单。而且这样的主程序根本就不需要改动。需要插件时,拿来就能用,插件更新时,也只需更新这个插件即可。

  从程序开发这角度,一般是先开发主程序,决定哪些功能由主程序来完成,然后再建立接口,申明接口的内容,这些内容决定着插件功能的扩展及方向的。这些都是有主程序开发者预先准备好的。插件开发者,从主程序开发者那里得到接口的内容,并书写继承这些接口的类,来完成具体的功能。

  下面来写个例子,这个例子没实际意义,纯属学习思想。例子是网上的经过自己改造的,发现别人某些地方不合理。

  首先,新建一个类库,里面定义接口,这里定义两个方法,一个有返回值的,一个无返回值的。

using System;
using System.Collections.Generic;
using System.Text;

namespace IMsg
{

///<summary>

/// 这是插件必须实现的接口,也是主程序与插件通信的唯一接口

/// 换句话说,主程序只认识插件里的这些方法

///</summary>

public interface IMsgPlug

{

  void OnShowDlg();

  string OnShowInfo();

}

}

  将上面的类库生成IMsg.dll, 新建一个类库MYPlugin1,添加刚出的引用,分别新建两个类来实现IMsg中定义的接口。

using System;
using System.Collections.Generic;
using System.Text;
using IMsg;
namespace MYPlugin1
{

public class myConsole : IMsgPlug

{

#region IMsgPlug 成员

public void OnShowDlg()

{

Console.WriteLine("控制台调用插件的OnShowDlg方法");

}

public string OnShowInfo()

{

return"myConsole";

}

#endregion

}

}

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using IMsg;
namespace MYPlugin1
{

publicclass MYDlg:Form,IMsgPlug

{

#region IMsgPlug 成员

public void OnShowDlg()

{

this.Text ="插件子窗体";

this.ShowDialog();//调用FormShowDialog,显示窗体

}

public string OnShowInfo()

{

return"MyDlg";

}

#endregion

}

}

  将上面的都生成dll, 生成目录可以设置为新建exe工程的bin目录plugins文件夹下。Plugins文件夹是新建的,专门存放插件的。 新建一个 WinForm项目来使用刚才的插件.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Collections;
using System.IO;
using System.Reflection;
namespace MsgBoxMain
{

publicpartialclass FormMain : Form

{

///<summary>

/// 存放插件的集合

///</summary>

private ArrayList plugins =new ArrayList();

public FormMain()

{

InitializeComponent();

}

///<summary>

/// 载入所有插件

///</summary>

privatevoid LoadAllPlugs()

{

//获取插件目录(plugins)下所有文件

string[] files = Directory.GetFiles(Application.StartupPath +@"\plugsins");

foreach (string file in files)

{

if (file.ToUpper().EndsWith(".DLL"))

{

try

{

//载入dll

Assembly ab = Assembly.LoadFrom(file); //加载一个程序集,即加载一个DLL,用了反射

Type[] types = ab.GetTypes();

foreach (Type t in types)

{

//如果某些类实现了预定义的IMsg.IMsgPlug接口,则认为该类适配与主程序(是主程序的插件)

if (t.GetInterface("IMsgPlug")!=null)

{

plugins.Add(ab.CreateInstance(t.FullName)); //创建一个实例并放到队列中

listBox1.Items.Add(t.FullName);

}

}

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

}

}

}

}


privatevoid btnLoadPlug_Click(object sender, EventArgs e)

{

LoadAllPlugs();

}


//调用插件的方法

privatevoid btnExecute_Click(object sender, EventArgs e)

{

if (this.listBox1.SelectedIndex ==-1return;

object selObj =this.plugins[this.listBox1.SelectedIndex];

Type t = selObj.GetType();

MethodInfo OnShowDlg = t.GetMethod("OnShowDlg");//发现方法的属性并提供方法元数据的访问

MethodInfo OnShowInfo = t.GetMethod("OnShowInfo");

OnShowDlg.Invoke(selObj, null);\\微软提供了Invoke的方法,其作用就是让子线程告诉窗体线程来完成相应的控件操作。Invoke方法会顺着控件树向上搜索,直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。Invoke方法会顺着控件树向上搜索,直到找到创建控件的那个线程(通常是主线程),然后进入那个线程改变控件的外观,确保不发生线程冲突。

object returnValue = OnShowInfo.Invoke(selObj, null);\\这个是有返回值的

this.lblMsg.Text = returnValue.ToString();

}

}

}

请注意插件实例是使用Sytem.Reflection.Assembly类的CreateInstance方法创建的。对比前面我提到过的UDP类的实例创建方法,我并没有在主程序中添加对Illegal.DLL的引用,程序中也没有直接对IllegalQuery类进行声明的代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值