浅析c#插件程序研究

c#语言可以开发许多程序插件,其中包括浏览器插件等等。

by the way,说起插件,

我们首先想到的是遨游浏览器,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();

}
}
}

  运行结果:

下面讨论插件代码:

if (itemStr =="myConsole")

{//调用存储在动态数组plugins里面的插件对象的OnShowInfo方法

string msgInfo = ((IMsgPlug)plugins[ListItems.SelectedIndex]).OnShowInfo();

MessageBox.Show(msgInfo, "MYPlugin1", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

elseif (itemStr =="MYDlg")//调用存储在动态数组plugins里面的插件对象的OnShowDlg方法

{

((IMsgPlug)plugins[ListItems.SelectedIndex]).OnShowDlg();

}

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

end

时间: 2024-08-01 18:19:55

浅析c#插件程序研究的相关文章

拨云浅析:小程序驱动微信生态?

拨云小编来带大家浅析一下,小程序驱动微信生态?自从小程序上线后,用户和从业人员对小程序的认知和解读不断的发生变化,从看好到看衰到再次看好,心路历程跌宕起伏. 微信生态这个词被越来越多的提及.之所以称之为生态,是因为它是健康的.包容的.能带来更多生命的. 虽然微信却只是一个社交软件,但目前微信已不再只是一个产品,它已发展成有创造新生命能力的生态系统. 成为一个生态,需要两个基本条件:「生命」和「生存环境」.生存环境是基础,生命是生态存在的证明. 张小龙在阐述微信的理念时说,微信所要打造的是一片森林

Android应用程序插件化研究之AssertManager

最近在研究Android应用的插件化开发,看了好几个相关的开源项目.插件化都是在解决以下几个问题: 如何把插件apk中的代码和资源加载到当前虚拟机. 如何把插件apk中的四大组件注册到进程中. 如何防止插件apk中的资源和宿主apk中的资源引用冲突. 就这几个问题,我开始研究插件化开发实现的相关技术. 在上篇文章中我讲了如何把插件apk中的class加载到当前进程 的问题,本篇文章主要讲第一点的第二点:如何加载另一个apk中的资源到当前应用中. AssetManager介绍 当我们在组件中获取资

病毒木马查杀实战第026篇:“白加黑”恶意程序研究(上)

前言 众所周知,传统的恶意程序都是由单一文件构成的,从而实现某一种或者几种恶意功能.而这类的恶意程序为了避免被发现以及被查杀,往往会采用五花八门的自我隐藏技术以及免杀技术,病毒程序的作者很多时候也是脑洞大开,为了对抗杀软的查杀也是无所不用其极.我们每天所处理的恶意文件里面,反查杀手段运用得最好的就是脚本木马,关于这类程序,我在之前的<病毒木马查杀实战第025篇:JS下载者脚本木马的分析与防御>这篇博文中也做过简单的论述.可是,不论恶意程序如何进化,杀软厂商总有各种各样的方法来应对现有的以及未知

android插件化研究

使用 android:sharedUserId="com.wallj.skin" 1.总共三个工程,包名分别为com.wallj.main/com.wallj.spring/com.wallj.summer 其中com.wallj.main为主工程,其他两个为插件工程,均只为主工程提供资源. 三个工程需要使用同一个 android:sharedUserId=" com.wallj.skin"以达到资源共享的目的. 设置了该属性后,三个工程之间的ClassLoader

一个插件程序的制作过程(一)

0x00 前言 其实做插件相关的程序是我梦寐以求的东西,很早我就开始设想,但是那时候还不会C#,C++又比较晦涩难懂,微软的组件技术还停留在COM+的水平上,自己设计插件系统的学习成本实在太大.所以就一直憋着憋着.现在上手学C#才发现,反射是一个好用的东西,它他适合做组件化程序了. 于是我就开始做了一个简单的Demo. 1 class Program 2 { 3 static string[] _methods; 4 static string _PluginName; 5 static str

这里想经过一个小程序研究标准库为 vector 对象提供的内存分配策,因为vector容器比list和deque容器用的很多,而且它的存储方式是连续的

我写一个简单的程序来区分vector容器size()和capacity()函数,这里capacity函数就是为vector容器预留了空间,不需要每次增添元素就要重新分配内存,这样效率上提高了很多,我通过一个间的小程序来研究,下面是程序和运行结果,比较简明可以看出capacity的大小都会比size大,因为size 指容器当前拥有的元素个数:而 capacity 则指容 器在必须分配新存储空间之前可以存储的元素总数.废话不多说,附上代码和运行结果:#include"stdafx.h" #

iOS插件化研究之一——JavaScriptCore

原文:http://chentoo.com/?p=191 一.前言 一样的开篇问题,为什么要研究这个?iOS为什么要插件化?为什么要借助其他语言比如html5 js甚至脚本lua等来实现原本OC/Swift应该实现的东西? 原因可以归结为两点: 1. iOS平台 appstore 审核速度不可控,而很多活动页面需要频繁更新,如果每次更新都走appstore审核流程,那活动也就不要做了. 2. 可多平台复用代码,节省开发成本.比如同一个活动的页面,用html5+js完成,就可以通用的在iOS An

浅析java基本程序

1.包 package package语法:包名.类名 ;包名的写法规范:所有字母需小写. 当然也可以采用静态导入  例如 import static java.lang.Math.* 有包的对象不能使用默认包的对象. import java.lang  包是java虚拟机自动导入的包,在使用java.lang包时我们可以不需要导包:例如:Thread类,Exception类,System类,String类等,可以相应的查看Api. java.util.*  这里的*表示java.util下的所

unity(Exploder插件)研究

哎 好久没写博客了 不是因为最近忙 而是比较懒 学的东西不深入 前段时间发现一个很好用的插件叫Exploder(是一个可以制作任何物体的爆炸效果) 好!我们开始我们的炸学校旅程!(O(∩_∩)O哈哈~ 开玩笑了) 不过这次我们使用的模型就是一个学校模型 首先:我们在学校中安装一个炸弹 --将插件中的Exploder预制体拖进去 选中要爆炸的物体 tag层设置为Exploder 开始撸代码~~~ using System.Collections; using System.Collections.