外掛架構、模組化系統、延遲載入非核心組件、測試框架自動發現測試類別等,均需在執行期動態載入組件並實例化型別、呼叫方法。
// 專案名: ReflectTarget, 輸出 ReflectTarget.dll
namespace ReflectTarget
{
public class Calculator
{
public Calculator() { Console.WriteLine("Calculator 建構子執行"); }
public int Add(int a, int b) => a + b;
public string GetMessage(string name) => $"Hello, {name} from DLL!";
public static string StaticMethod() => "Static method called.";
}
}
編譯後取得 ReflectTarget.dll。
using System;
using System.Reflection;
using System.IO;
class Program
{
static void Main()
{
string dllPath = @"C:\Path\To\ReflectTarget.dll"; // 實際路徑
if (!File.Exists(dllPath))
{
Console.WriteLine("DLL 不存在");
return;
}
// 1. 載入組件 (三種方式擇一)
// Assembly asm = Assembly.LoadFile(dllPath); // 完整路徑載入,不進入載入上下文
// Assembly asm = Assembly.LoadFrom(dllPath); // 載入上下文,解析相依性較好
Assembly asm = Assembly.Load(File.ReadAllBytes(dllPath)); // 位元組陣列載入,最隔離
// 2. 取得型別 (需含命名空間)
Type calcType = asm.GetType("ReflectTarget.Calculator");
if (calcType == null)
{
Console.WriteLine("找不到型別");
return;
}
// 3. 建立實例 (無參數建構子)
object instance = Activator.CreateInstance(calcType);
// 若有參數建構子:Activator.CreateInstance(calcType, arg1, arg2);
// 4. 呼叫實例方法
MethodInfo addMethod = calcType.GetMethod("Add");
int result = (int)addMethod.Invoke(instance, new object[] { 10, 20 });
Console.WriteLine($"Add(10,20) = {result}");
MethodInfo msgMethod = calcType.GetMethod("GetMessage");
string msg = (string)msgMethod.Invoke(instance, new object[] { "Alice" });
Console.WriteLine(msg);
// 5. 呼叫靜態方法 (instance 可傳 null)
MethodInfo staticMethod = calcType.GetMethod("StaticMethod");
string staticResult = (string)staticMethod.Invoke(null, null);
Console.WriteLine(staticResult);
}
}
| 需求 | API | 備註 |
|---|---|---|
| 載入檔案路徑 | Assembly.LoadFile(path) | 不解析相依組件,隔離性高 |
| 載入並解析相依 | Assembly.LoadFrom(path) | 進入 LoadFrom 上下文 |
| 載入位元組陣列 | Assembly.Load(byte[]) | 記憶體中載入,無檔案鎖定 |
| 取得型別 | asm.GetType("Full.Name") | 區分大小寫,需含命名空間 |
| 建立實例 | Activator.CreateInstance(type) | 支援建構子參數 |
| 取得方法 | type.GetMethod("Name") | 可加 BindingFlags 找私有/靜態/多載 |
| 呼叫方法 | method.Invoke(obj, args[]) | 靜態方法 obj 傳 null |
instance as IPlugin 強型別呼叫,避免反射效能損耗。method.MakeGenericMethod(typeof(T)).Invoke(...)。GetMethod("Name", BindingFlags.NonPublic | BindingFlags.Instance)。AppDomain 載入,卸載時 AppDomain.Unload(domain)。.NET Core 3.0+ 支援 AssemblyLoadContext 卸載。| 例外 | 原因 | 解決 |
|---|---|---|
| FileNotFoundException | 相依 DLL 找不到 | 將相依 DLL 放同目錄、或處理 AssemblyResolve 事件 |
| MissingMethodException | 方法簽章不符、建構子參數錯誤 | 檢查 GetMethod 參數、BindingFlags、建構子參數順序 |
| TargetInvocationException | 方法內部拋出例外 | 捕獲 ex.InnerException 才是真正原因 |
| BadImageFormatException | 位元數不符 (x86/x64) | 專案目標平台與 DLL 一致,或用 CorFlags 強制 |
原文連結:https://www.bianceng.cn/Programming/csharp/201410/45595.htm