UI 界面提供兩個下拉框:第一個選擇類類型 (A/B),第二個動態顯示該類的公共方法列表,用戶選擇方法後點擊執行,實現插件式調用架構。
// 假設類在當前程序集中
Type type = Type.GetType("MyNamespace." + className); // 如 "MyNamespace.ClassA"
// 或從程序集查找
// Type type = Assembly.GetExecutingAssembly().GetTypes().First(t => t.Name == className);
object instance = Activator.CreateInstance(type); // 無參構造函數
// 有參構造函數
// object instance = Activator.CreateInstance(type, new object[] { arg1, arg2 });
// 獲取所有公共實例方法
MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
// 綁定到第二個下拉框
comboMethods.DataSource = methods;
comboMethods.DisplayMember = "Name";
// 執行選中的方法
MethodInfo method = (MethodInfo)comboMethods.SelectedItem;
object result = method.Invoke(instance, null); // 無參方法
// 有參方法
// object result = method.Invoke(instance, new object[] { param1, param2 });
using System;
using System.Reflection;
using System.Windows.Forms;
namespace DynamicInvokeDemo
{
public class ClassA { public void MethodX() => MessageBox.Show("A.X"); public void MethodY(int n) => MessageBox.Show($"A.Y: {n}"); }
public class ClassB { public void MethodJ() => MessageBox.Show("B.J"); public string MethodK(string s) => $"B.K: {s}"; }
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
// 初始化類下拉框
cmbClass.Items.AddRange(new[] { "ClassA", "ClassB" });
cmbClass.SelectedIndexChanged += CmbClass_SelectedIndexChanged;
btnInvoke.Click += BtnInvoke_Click;
}
private void CmbClass_SelectedIndexChanged(object sender, EventArgs e)
{
string className = cmbClass.SelectedItem.ToString();
Type type = Type.GetType($"DynamicInvokeDemo.{className}");
if (type == null) return;
// 獲取公共實例方法 (排除 Object 繼承方法)
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
cmbMethod.DataSource = methods;
cmbMethod.DisplayMember = "Name";
}
private void BtnInvoke_Click(object sender, EventArgs e)
{
if (cmbClass.SelectedItem == null || cmbMethod.SelectedItem == null) return;
try
{
string className = cmbClass.SelectedItem.ToString();
Type type = Type.GetType($"DynamicInvokeDemo.{className}");
object instance = Activator.CreateInstance(type);
MethodInfo method = (MethodInfo)cmbMethod.SelectedItem;
// 簡單參數處理:演示用,實際需根據 ParameterInfo 動態構建 UI
object[] parameters = null;
if (method.GetParameters().Length > 0)
{
// 這裡簡單處理:彈窗輸入
string input = Microsoft.VisualBasic.Interaction.InputBox("請輸入參數 (多個用逗號分隔):", "參數輸入");
parameters = input.Split(',').Select(s => s.Trim()).ToArray();
}
object result = method.Invoke(instance, parameters);
if (result != null)
MessageBox.Show($"執行結果: {result}");
}
catch (Exception ex)
{
MessageBox.Show($"調用失敗: {ex.Message}");
}
}
}
}
public interface IPlugin
{
string Name { get; }
string Description { get; }
void Execute(PluginContext context);
}
public class PluginContext
{
public Dictionary Parameters { get; } = new();
public IServiceProvider Services { get; set; }
}
[AttributeUsage(AttributeTargets.Class)]
public class PluginAttribute : Attribute
{
public string Category { get; set; }
public int Priority { get; set; }
}
[Plugin(Category = "DataProcess", Priority = 1)]
public class ExportExcelPlugin : IPlugin { ... }
public class PluginManager
{
private readonly List _plugins = new();
public void LoadPlugins(string pluginDirectory)
{
foreach (var dll in Directory.GetFiles(pluginDirectory, "*.dll"))
{
var asm = Assembly.LoadFrom(dll);
foreach (var type in asm.GetTypes())
{
if (typeof(IPlugin).IsAssignableFrom(type) && !type.IsInterface)
{
var plugin = (IPlugin)Activator.CreateInstance(type);
_plugins.Add(plugin);
}
}
}
_plugins.Sort((a,b) => {
var attrA = a.GetType().GetCustomAttribute();
var attrB = b.GetType().GetCustomAttribute();
return (attrB?.Priority ?? 0).CompareTo(attrA?.Priority ?? 0);
});
}
public IReadOnlyList Plugins => _plugins.AsReadOnly();
}
| 問題 | 解決方案 |
|---|---|
| 頻繁反射調用慢 | 緩存 MethodInfo/ConstructorInfo;使用 Delegate.CreateDelegate 生成強類型委托 |
| 表達式樹編譯 | 將反射調用封裝為 `Func |
| 動態方法 | 使用 System.Reflection.Emit.DynamicMethod 生成 IL 代碼,繞過訪問檢查 |
Assembly.LoadFrom 簽名驗證或運行在沙箱/AppDomain 隔離