C#反射實現(xiàn)插件式開發(fā)的過程詳解
前言
插件式架構(gòu),一種全新的、開放性的、高擴展性的架構(gòu)體系。插件式架構(gòu)設(shè)計好處很多,把擴展功能從框架中剝離出來,降低了框架的復(fù)雜度,讓框架更容易實現(xiàn)。擴展功能與框架以一種很松的方式耦合,兩者在保持接口不變的情況下,可以獨立變化和發(fā)布。基于插件設(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ā)的可擴展性,靈活性比較高,而且可以進(jìn)行定制化開發(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ù)庫操作,以提高代碼的可維護(hù)性和復(fù)用性,感興趣的朋友一起看看吧2024-08-08

