一:解决方案管理器截图
二:简单功能说明
IMsg定义了一个接口,MYPlugin1实现接口功能,”插件式开发“实现程序运行时再调用非本身引用的dll文件,调用该dll的方法实现功能
三:IMsg、MYPlugin1(class1和class2)和插件式开发的代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace IMsg { ///<summary> /// 这是插件必须实现的接口,也是主程序与插件通信的唯一接口 /// 换句话说,主程序只认识插件里的这些方法 ///</summary> public interface IMsgPlug { void OnShowDlg(); string OnShowInfo(); } }
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 } }
程序的主要、重要代码
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections; using System.IO; using System.Reflection; namespace 插件式开发 { /// <summary> /// MainWindow.xaml 的交互逻辑 /// </summary> public partial class MainWindow : Window { // 存放插件的集合 private ArrayList plugins =new ArrayList(); public MainWindow() { InitializeComponent(); } ///<summary> /// 载入所有插件 ///</summary> private void LoadAllPlugs() { //获取插件目录(plugins)下所有文件 // string[] files = Directory.GetFiles(Application.ResourceAssembly + @"\plugins"); //string str6 = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;//获得到debug的文件夹 //str6 = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;//获得到exe文件 //str6 = System.Environment.CurrentDirectory;//获得到debug的文件夹 //str6 = System.IO.Directory.GetCurrentDirectory();//获得到debug的文件夹 //str6 = System.AppDomain.CurrentDomain.BaseDirectory;//获得到debug的文件夹 //str6 = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;//获得到debug的文件夹 //str6 = System.Windows.Forms.Application.StartupPath;//获得到debug的文件夹 //string[] files = Directory.GetFiles(AppDomain.CurrentDomain +"plugins"); string[] files = Directory.GetFiles(@"E:\练习代码\IMsg\插件式开发\plugins");//得到dll文件的存放路径 foreach (string file in files) { if (file.ToUpper().EndsWith(".DLL"))//如果文件以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));//将实例化的dll加入到泛型集合中 lstWays.Items.Add(t.FullName);//显示在listbox中 } } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } } //窗体载入事件 private void Window_Loaded(object sender, RoutedEventArgs e) { LoadAllPlugs(); } //调用插件的方法 private void btnGetIn_Click(object sender, RoutedEventArgs e) { if (this.lstWays.SelectedIndex == -1) return; object selObj = this.plugins[this.lstWays.SelectedIndex]; Type t = selObj.GetType(); MethodInfo OnShowDlg = t.GetMethod("OnShowDlg");//得到dll文件的中的方法 MethodInfo OnShowInfo = t.GetMethod("OnShowInfo");//得到dll文件的中的方法 OnShowDlg.Invoke(selObj, null);//方法调用参数 object returnValue = OnShowInfo.Invoke(selObj, null); } } }
四:后记
提起插件式,我们首先想到的是firefox, 用过firefox的人都知道它是一个插件式程序。当一个功能需要,完全可以从网上下载一个插件后,重启后,就能使用。这个功能给我们带来许多的方便之处,这就是插件式程序的好处。
插件的本质在于不修改程序主体(平台)的情况下对软件功能进行拓展与加强,当插件的接口公开后,任何公司或个人都可以制作自己的插件来解决一些操作上的不便或增加新功能,也就是真正意义上实现“即插即用”软件开发。
平台+插件软件结构是将一个待开发的目标软件分为两部分,一部分为软件的主体或框架,可定义为平台,这是预先编译后的程序。另一部分为功能或补充模块,可定义为插件。这个就是后来要进行安装的插件程序。
假设你的程序已经部署在用户的计算机上,并且能够正常运行了。但是有一天,用户打来电话——他们需要增加新的功能。确定了用户的需求后,你竟然发现原有的软件架构已经无法胜任新增任务的需求——你需要重新设计这个应用了!但问题是,就算你又用了一个开发周期完成了用户需要的应用,切不能保证用户的需求不会再次变更。也就是说,需求蔓延的可能性依然存在。因此,这种情况下插件架构更能显示出它的优越性。
可以这么说,用它可以带来方便的地方,而且开发它,也很简单。而且这样的主程序根本就不需要改动。需要插件时,拿来就能用,插件更新时,也只需更新这个插件即可。
从程序开发这角度,一般是先开发主程序,决定哪些功能由主程序来完成,然后再建立接口,申明接口的内容,这些内容决定着插件功能的扩展及方向的。这些都是有主程序开发者预先准备好的。插件开发者,从主程序开发者那里得到接口的内容,并书写继承这些接口的类,来完成具体的功能。