程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 淺析C#插件式程序開發經驗

淺析C#插件式程序開發經驗

編輯:關於C語言
什麼是插件式編程

  提起插件式,我們首先想到的是firefox,用過Firefox的人都知道它是一個插件式程序。當一個功能需要,完全可以從網上下載一個插件後,重啟後,就能使用。這個功能給我們帶來許多的方便之處,這就是插件式程序的好處。

  插件的本質在於不修改程序主體(平台)的情況下對軟件功能進行拓展與加強,當插件的接口公開後,任何公司或個人都可以制作自己的插件來解決一些操作上的不便或增加新功能,也就是真正意義上實現“即插即用”軟件開發。

  平台+插件軟件結構是將一個待開發的目標軟件分為兩部分,一部分為軟件的主體或框架,可定義為平台,這是預先編譯後的程序。另一部分為功能或補充模塊,可定義為插件。這個就是後來要進行安裝的插件程序。

  假設你的程序已經部署在用戶的計算機上,並且能夠正常運行了。但是有一天,用戶打來電話——他們需要增加新的功能。確定了用戶的需求後,你竟然發現原有的軟件架構已經無法勝任新增任務的需求——你需要重新設計這個應用了!但問題是,就算你又用了一個開發周期完成了用戶需要的應用,切不能保證用戶的需求不會再次變更。也就是說,需求蔓延的可能性依然存在。因此,這種情況下插件架構更能顯示出它的優越性。

  可以這麼說,用它可以帶來方便的地方,而且開發它,也很簡單。而且這樣的主程序根本就不需要改動。需要插件時,拿來就能用,插件更新時,也只需更新這個插件即可。

  從程序開發這角度,一般是先開發主程序,決定哪些功能由主程序來完成,然後再建立接口,申明接口的內容,這些內容決定著插件功能的擴展,及方向的。這些都是有主程序開發者預先准備好的。插件開發者,從主程序開發者那裡得到接口的內容,並書寫繼承這些接口的類,來完成具體的功能。

  下面來寫個例子,這個例子沒實際意義,純屬學習思想。例子是網上的經過自己改造的,發現別人某些地方不合理。

  首先,新建一個類庫,裡面定義接口,這裡定義兩個方法,一個有返回值的,一個無返回值的。

  using System;

  using System.Collections.Generic;

  using System.Text;

  namespace IMsg{

  ///

  /// 這是插件必須實現的接口,也是主程序與插件通信的唯一接口

  /// 換句話說,主程序只認識插件裡的這些方法

  ///

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 { ///

/// 存放插件的集合 /// private ArrayList plugins = new ArrayList(); public FormMain() { InitializeComponent(); } /// /// 載入所有插件 /// 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 下載,就可以直接使用了,以前的接口都定義好了,新的實現類也就是不可預料的,因此不能在主程序實例化實現接口的類,這樣違背了插件的初衷。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved