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
{
public class MYDlg:Form,IMsgPlug
{
#region IMsgPlug 成员

public void OnShowDlg()
{
this.Text = "插件子窗体";
this.ShowDialog();//调用Form的ShowDialog,显示窗体
}

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
{
public partial class FormMain : Form
{

/// <summary>
/// 存放插件的集合
/// </summary>
private ArrayList plugins = new ArrayList();
public FormMain()
{
InitializeComponent();
}

/// <summary>
/// 载入所有插件
/// </summary>
private void 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);
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);
}
}
}

}

private void btnLoadPlug_Click(object sender, EventArgs e)
{
LoadAllPlugs();
}

//调用插件的方法
private void btnExecute_Click(object sender, EventArgs e)
{
if (this.listBox1.SelectedIndex == -1) return;
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);
object returnValue = OnShowInfo.Invoke(selObj, null);
this.lblMsg.Text = returnValue.ToString();

}
}
}

运行结果:

这里与网上那位原创的仁兄的看法不同(原文链接http://blog.csdn.net/jam12315/archive/2008/08/18/2791534.aspx),可供大家讨论。

原文有 这样的一段:

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();
                }

我认为既然是插件,就应该是动态加载的,客户端肯定不能判断 itemStr,因为实现接口的类是不可预料的,因此主程序不应该添加对IMsg的引用,也不应该在客户端实例化插件对象,因为插件开发的初衷是为了以后更新的时候不更改主程序,只提供对应的dll 下载,就可以直接使用了,以前的接口都定义好了,新的实现类也就是不可预料的,因此不能在主程序实例化实现接口的类,这样违背了插件的初衷。

时间: 2024-11-05 01:26:40

C# 插件式开发的相关文章

也来学学插件式开发

上一家公司有用到插件式开发来做一个工具箱,类似于QQ电脑管家,有很多工具列表,点一下工具下载后就可以开始使用了.可惜在那家公司待的时候有点短,没有好好研究一下.现在有空,自己在网上找了些资料,也来试试. 主要思路:公开一个插件接口,如果.DLL或.EXE的代码中有继承这个接口就将其示为插件,并将这些插件放在同一目录.运行程序的时候扫描目录并通过反射判断.DLL或.EXE中是否存在该接口,若存在,则当作插件加载进来. 我们来做一个示例看看.例子也是在园子里找的,自己改了一下,详见:http://w

Android应用插件式开发解决方法

Android应用插件式开发解决方法 一.现实需求描述 一般的,一个Android应用在开发到了一定阶段以后,功能模块将会越来越多,APK安装包也越来越大,用户在使用过程中也没有办法选择性的加载自己需要的功能模块.此时可能就需要考虑如何分拆整个应用了. 二.解决方案提出 一般有两种方式,一种是将应用按照功能分拆成多个应用,用户需要哪个就下载哪个,都需要就都下载.应用之间,可以在代码层面做一定的关联,以共享部分信息.另一种方式,类似于其他平台插件的方式,用户可以在主应用中可以选择性的下载需要的插件

MVC 插件式开发

在开发一个OA系统是,我们可能遇到 A模块. B模块 .C模块,这也模块组成一个完整的系统,买给客服.现在又有一个客服要我们做一个OA系统,唉我们发现,跟上一个OA系统差不多,但没有C模块.怎么办? 修改源码,系统简单还好,但是一系统复杂到一定程度,修改源码改这改这就像重写了! 怎么办,MVC插件式开发帮你解决问题,先看演示,再看代码.CCAV.WebSite 是主站,引用 CCAV.Modules.Category CCAV.Modules.Category 就像当于一个模块,具体看演示. 通

基于AppDomain的&quot;插件式&quot;开发

很多时候,我们都想使用(开发)USB式(热插拔)的应用,例如,开发一个WinForm应用,并且这个WinForm应用能允许开发人员定制扩展插件,又例如,我们可能维护着一个WinService管理系统,这个WinService系统管理的形形色色各种各样的服务,这些服务也是各个"插件式"的类库,例如: public interface IJob { void Run(DateTime time); } public class CollectUserInfo : IJob { public

android基于插件式开发

之前没有听过app插件式开发今天就做一下学习的笔记.这里的插件式开发通俗的讲就是把一个很大的app分成n多个比较小的app,其中有一个app是主app.网上查了一下采用了这种开发模式的有支付宝客户端.QQ换肤其他的就不得而知了有人说微信也是基于插件的但是微信在更新的时候会下载全部的应用程序把旧的完全覆盖所以猜想应该目前不是吧. 基于插件的开发列举两个比较突出的优点: 1.应用程序非常容易扩招,比如有一个新的领域要加到旧的应用程序中来只需把这个新的领域做为一个插件,只开发这个小的app就可以了旧的

使用Arcmap为宿主程序进行插件式开发时调用Arcmap自身进度条的问题

问题:使用Arcmap为宿主程序进行插件式开发时(选择Extendding ArcObjects模板)调用Arcmap自身进度条. 解决方法: 1 //获得IStepProgressor 进度条,并进行初始设置 2 IStepProgressor stepProgressor = m_application.StatusBar.ProgressBar; 3 stepProgressor.MinRange = 1; 4 stepProgressor.MaxRange = 10000; 5 6 //

关于安卓插件式开发

网上找了很多关于插件式开发的资料  最值得研究意义的两种开源开发插件框架http://www.oschina.net/p/cjframeforandroid 与http://www.oschina.net/p/xcombine    另外还有一种非常简单的通过sharedUserId方式去实现.接下来讲的就是最方便的通过sharedUserId去实现. 思路:在主app中与次app中设置同样的sharedUserId,在主app中通过这个id 找到其他次app的包名,通过包名开启其他次app.

Android应用插件式开发解决方法[转]

一.现实需求描述 一般的,一个Android应用在开发到了一定阶段以后,功能模块将会越来越多,APK安装包也越来越大,用户在使用过程中也没有办法选择性的加载自己需要的功能模块.此时可能就需要考虑如何分拆整个应用了. 二.解决方案提出 一般有两种方式,一种是将应用按照功能分拆成多个应用,用户需要哪个就下载哪个,都需要就都下载.应用之间,可以在代码层面做一定的关联,以共享部分信息.另一种方式,类似于其他平台插件的方式,用户可以在主应用中可以选择性的下载需要的插件,不需要该功能,则不需要下载. 第一种

关于dynamic-load插件式开发

dynamic-load插件式开发可以访问没有安装的APK中的类,也就是APK无需安装就可以被打开.具体原理有相关文档参考  http://blog.csdn.net/singwhatiwanna/article/details/22597587 其中有一些缺陷,插件中无法调用系统相册或者相机等,只要是用到intent调用系统acitivity都是行不通的. dynamic-load有三种开发模式,第一种是主程序与插件没有交互完全独立开发的,第二种是插件可以调用主程序提供的接口(因为插件中不支持

MVC插件式开发平台

---恢复内容开始--- 经过DyOS.BraveOS1.0再到BraveOS2.0,系统现在已经开发了下载. 我们的目标是,网页版操作系统,可以在线安装更新软件,并提供二次开发平台,提供基础的逻辑和控件,我们将在后期公开开发文档,如果您不会html5,不会自己写js插件,那么这将是您的福音,因为,这些事我们会为你来更新完善!您只管用就行,哈哈. 我们的系统不支持IE这个老东西,支持谷歌内核所有浏览器. 由于官方网站即将发布,将随官方网站和二次开发文档一起发布,请持续关注www.braveos.