反射允許執行期檢查中繼資料、動態載入組件、建立型別實例並呼叫成員。本文示範完整流程:編譯類別庫 DLL、主程式 Assembly.LoadFile、GetType、CreateInstance、GetMethod、Invoke 呼叫無參/有參/靜態/實例方法。
新增 Class Library 專案 Webtest,加入類別 ReflectTest:
namespace Webtest
{
public class ReflectTest
{
public ReflectTest() { }
public string WriteString(string s) => "歡迎您," + s;
public static string WriteName(string s) => "歡迎您光臨," + s;
public string WriteNoPara() => "您使用的是無參數方法";
}
}
編譯產出 TestReflect.dll。
using System.Reflection;
public void TestReflection()
{
try
{
// 1. 載入組件
Assembly asm = Assembly.LoadFile(@"D:\TestReflect.dll");
// 2. 取得型別(需完整命名空間.類別名)
Type type = asm.GetType("Webtest.ReflectTest");
// 3. 建立實例(實例方法需實例)
object obj = asm.CreateInstance("Webtest.ReflectTest");
// 4. 取得方法並呼叫
// 實例方法
MethodInfo mi = type.GetMethod("WriteString");
string result = (string)mi.Invoke(obj, new object[] { "江立俊" });
Console.WriteLine(result); // 歡迎您,江立俊
// 靜態方法:第一參數傳 null
mi = type.GetMethod("WriteName");
result = (string)mi.Invoke(null, new object[] { "江立俊" });
Console.WriteLine(result); // 歡迎您光臨,江立俊
// 無參實例方法
mi = type.GetMethod("WriteNoPara");
result = (string)mi.Invoke(obj, null);
Console.WriteLine(result); // 您使用的是無參數方法
}
catch (Exception ex)
{
Console.WriteLine("反射錯誤:" + ex.Message);
// 實務上記錄 ex.ToString() 含堆疊追蹤
}
}
| 需求 | API | 備註 |
|---|---|---|
| 載入檔案組件 | Assembly.LoadFile(path) | 需完整路徑,不驗證證據;LoadFrom 會進入 LoadFrom 上下文 |
| 依名稱取得型別 | asm.GetType("Ns.Class") | 大小寫敏感,找不到回傳 null |
| 建立實例 | asm.CreateInstance("Ns.Class") / Activator.CreateInstance(type) | 呼叫無參建構子;有參用 Activator.CreateInstance(type, args) |
| 取得方法 | type.GetMethod("Name") / GetMethods() | 多載需用 GetMethod("Name", types[]) |
| 呼叫方法 | mi.Invoke(obj, args[]) | 靜態方法 obj 傳 null;傳回值需轉型 |
| 取得屬性/欄位 | type.GetProperty/Field → GetValue/SetValue |
mi.MakeGenericMethod(typeArgs[]).Invoke(...)。BindingFlags.NonPublic | BindingFlags.Instance。MethodInfo、PropertyInfo,或用 Delegate.CreateDelegate、Expression 樹、FastMember 套件。AssemblyLoadContext:.NET Core 3.0+ 支援組件隔離載入/卸載,解決插件系統版本衝突。反射是 .NET 動態能力的基石,善用它能構建極具延展性的架構,但請謹記「快取中繼資料、避免熱路徑反射」的效能鐵律。