C#反射實現(xiàn)插件式開發(fā)的過程詳解
前言
插件式架構(gòu),一種全新的、開放性的、高擴展性的架構(gòu)體系。插件式架構(gòu)設(shè)計好處很多,把擴展功能從框架中剝離出來,降低了框架的復(fù)雜度,讓框架更容易實現(xiàn)。擴展功能與框架以一種很松的方式耦合,兩者在保持接口不變的情況下,可以獨立變化和發(fā)布?;诓寮O(shè)計并不神秘,相反它比起一團泥的設(shè)計更簡單,更容易理解。
項目介紹
書寫4個插件類庫,分別傳參實現(xiàn)“加減乘除”運算,調(diào)用插件的客戶端采用Winform窗體程序。
目標(biāo)框架: .NET Framework 4.6.1
項目架構(gòu)和窗體布局:
客戶端程序:
- PluginApp:反射調(diào)用插件
插件描述:
- PluginBase:規(guī)范插件的基類,定義抽象類,開發(fā)的插件的類需要繼承此類,代表遵守這個規(guī)范。
- CustomPlugInA:實現(xiàn)加法的插件
- CustomPlugInB:實現(xiàn)減法的插件
- CustomPlugInC:實現(xiàn)乘法的插件
- CustomPlugInD:實現(xiàn)除法的插件
代碼實現(xiàn)
插件基類
/// <summary> ///插件基類 /// </summary> public abstract class Base { /// <summary> /// 插件名稱 /// </summary> /// <returns></returns> public abstract string Name(); /// <summary> /// 插件描述 /// </summary> /// <returns></returns> public abstract string Desc(); /// <summary> /// 執(zhí)行方法 /// </summary> /// <param name="param1">參數(shù)1</param> /// <param name="param2">參數(shù)2</param> /// <returns></returns> public abstract string Run(int param1, int param2); /// <summary> /// 版本 /// </summary> public string Version { get { return "1.0.0"; } } }
PlugInA
public class PlugInA: Base { public override string Name() { return "PlugInA"; } public override string Desc() { return "加法"; } public override string Run(int param1,int param2) { return (param1 + param2) + ""; } } }
PlugInB
public class PlugInB : Base { public override string Name() { return "PlugInB"; } public override string Desc() { return "減法"; } public override string Run(int param1, int param2) { return (param1 - param2) + ""; } }
PlugInC
public class PlugInC : Base { public override string Name() { return "PlugInC"; } public override string Desc() { return "乘法"; } public override string Run(int param1, int param2) { return (param1 * param2) + ""; } }
PlugInD
public class PlugInD : Base { public override string Name() { return "PlugInD"; } public override string Desc() { return "除法"; } public override string Run(int param1, int param2) { return (param1 / param2) + ""; } }
客戶端核心代碼:
public partial class FrmMain : Form { public FrmMain() { InitializeComponent(); dgrvPlugins.AutoGenerateColumns = false; } List<PluginModel> List = new List<PluginModel>(); readonly string PlugInPath = Application.StartupPath + "\\PlugIns"; /// <summary> /// 載入插件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btLoadPlugins_Click(object sender, EventArgs e) { if (!Directory.Exists(PlugInPath)) { Directory.CreateDirectory(PlugInPath); } List.Clear(); string[] files = Directory.GetFiles(PlugInPath); foreach (string file in files) { if (file.ToLower().EndsWith(".dll")) { try { Assembly assembly = Assembly.LoadFrom(file); Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (type.BaseType.FullName == "PlugInBase.Base") { object obj = assembly.CreateInstance(type.FullName); string name = type.GetMethod("Name").Invoke(obj, null).ToString(); string desc = type.GetMethod("Desc").Invoke(obj, null).ToString(); string version = type.GetProperty("Version").GetValue(obj).ToString(); List.Add(new PluginModel { Name = name, Desc = desc, Version = version, type = type, Obj = obj }); } } } catch (Exception ex) { throw ex; } } } dgrvPlugins.DataSource = new BindingList<PluginModel>(List); } /// <summary> /// 打開插件目錄 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btOpenPluginDir_Click(object sender, EventArgs e) { Process.Start(PlugInPath); } /// <summary> /// 執(zhí)行選中插件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btExcute_Click(object sender, EventArgs e) { //獲取選擇的插件信息 int index = dgrvPlugins.CurrentRow.Index; object obj = List[index].Obj; Type type = List[index].type; //參數(shù) object[] inParams = new object[2]; inParams[0] =Convert.ToInt32( dgrvPlugins.CurrentRow.Cells[2].Value); inParams[1] = Convert.ToInt32(dgrvPlugins.CurrentRow.Cells[3].Value); object value = type.GetMethod("Run").Invoke(obj, inParams); MessageBox.Show(Convert.ToString(value),"結(jié)果",MessageBoxButtons.OK); } }
項目配置
插件生成配置
編譯生成項目的時候需要注意,此處的調(diào)用插件是通過反射調(diào)用.dll中類和方法,所以首先要找到這個.dll的文件,所以此處我們在Winform客戶端程序下建立一個存放類庫dll的文件 PlugIns
,在插件類庫項目生成后事件命令中,填入如下命令:
copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\PlugIns"
以上命令代表,在項目的類庫生成后,將類庫copy到解決方案的路徑子文件夾 PlugIns
,也就是我們建立存放自定義插件的文件夾。當(dāng)然,如果不怕麻煩,每次生成后,手動復(fù)制到此文件夾也可以,直接復(fù)制到客戶端程序的 ..\bin\PlugIns
文件夾下。
插件路徑配置
全選這些類庫,把這些類庫設(shè)置為"如果較新則復(fù)制",這樣每次在編譯客戶端程序,如果自定義插件有更新,則同步會復(fù)制到 bin
目錄下
插件基類配置
插件基類提供了規(guī)范,需要在類庫的生成后事件,添加命令:
copy /Y "$(TargetDir)$(ProjectName).dll" "$(SolutionDir)\bin\Debug"
將生成的dll文件,拷貝到客戶端程序的 bin
路徑下
調(diào)用演示CustomPlugInA
CustomPlugInB
CustomPlugInC
CustomPlugInD
插件開發(fā)優(yōu)缺點
- 把擴展功能從框架中剝離出來,降低了框架的復(fù)雜度,讓框架更容易實現(xiàn)
- 宿主中可以對各個模塊解析,完成插件間、插件和主程序間的通信。
- 插件開發(fā)的可擴展性,靈活性比較高,而且可以進行定制化開發(fā)。
缺點
- 每一個插件被編譯成了dll,各模塊無法單獨運行,必須依托于主程序。
- 修改插件時,由于生成的是dll,無法快速直觀的查看修改以及調(diào)試。
- 每一個插件必須依賴于某一個規(guī)范。
到此這篇關(guān)于C#反射實現(xiàn)插件式開發(fā)的文章就介紹到這了,更多相關(guān)C#反射插件式開發(fā)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C# 實現(xiàn)基于ADO.NET框架的DBHelper工具類(簡化數(shù)據(jù)庫操作)
ADO.NET是.NET框架中用于與數(shù)據(jù)庫交互的核心組件,提供了一套用于連接數(shù)據(jù)庫、執(zhí)行SQL查詢、插入、更新和刪除數(shù)據(jù)的類庫,包括SqlConnection、SqlCommand、SqlDataReader等,本文介紹如何使用DBHelper類封裝數(shù)據(jù)庫操作,以提高代碼的可維護性和復(fù)用性,感興趣的朋友一起看看吧2024-08-08