Reflection (反射) 是 .NET 執行時機制,允許程式在**執行期**檢視、操作組件中的型別中繼資料:類別、結構、介面、列舉、委派、方法、屬性、事件、建構子、欄位、屬性 (Attribute) 等。甚至能**動態建立實例、呼叫方法、存取私有成員**、實作外掛架構、序列化、ORM、單元測試框架等核心基礎設施。
AppDomain (應用程式域)
└─ Assembly (組件) ── .dll / .exe
└─ Module (模組)
└─ Type (型別) ── Class / Struct / Interface / Enum / Delegate
├─ ConstructorInfo (建構子)
├─ MethodInfo (方法)
├─ PropertyInfo (屬性)
├─ FieldInfo (欄位)
├─ EventInfo (事件)
└─ ParameterInfo (參數)
| 類別 | 常用靜態/實例方法 | 用途 |
|---|---|---|
Assembly | LoadFrom, Load, GetTypes, GetType, CreateInstance | 載入組件、列舉/取得型別、建立實例 |
Type | GetType, GetConstructors, GetMethods, GetProperties, GetFields, GetEvents, GetInterfaces, GetCustomAttributes | 型別中繼資料核心入口 |
Activator | CreateInstance(type), CreateInstance(type, args) | 動態建立實例 (支援建構子參數) |
MethodInfo | Invoke(obj, params), GetParameters, ReturnType | 動態呼叫方法 |
PropertyInfo | GetValue/SetValue(obj), PropertyType, CanRead/CanWrite | 動態存取屬性 |
FieldInfo | GetValue/SetValue(obj), FieldType, IsPublic/IsStatic | 動態存取欄位 (含私有) |
ConstructorInfo | Invoke(args), GetParameters | 動態呼叫建構子 |
// 1. 定義外掛介面 (雙方共用組件)
public interface IPlugin
{
string Name { get; }
void Execute(string input);
}
// 2. 外掛實作 (獨立組件 PluginA.dll)
public class PluginA : IPlugin
{
public string Name => "Plugin A";
public void Execute(string input) => Console.WriteLine($"[PluginA] 處理: {input}");
}
// 3. 主程式動態載入
public class PluginLoader
{
public IEnumerable LoadPlugins(string folderPath)
{
foreach (var file in Directory.GetFiles(folderPath, "*.dll"))
{
Assembly asm = null;
try { asm = Assembly.LoadFrom(file); }
catch { continue; } // 忽略非 .NET 或載入失敗
foreach (var type in asm.GetTypes())
{
if (typeof(IPlugin).IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
{
if (Activator.CreateInstance(type) is IPlugin plugin)
yield return plugin;
}
}
}
}
}
// 4. 使用
var loader = new PluginLoader();
foreach (var plugin in loader.LoadPlugins(@".\Plugins"))
{
Console.WriteLine($"載入: {plugin.Name}");
plugin.Execute("Hello Reflection");
}
| 技巧 | 說明 |
|---|---|
| Delegate 緩存 | 將 `MethodInfo` 轉為 `Func<,>` / `Action<,>` 緩存,避免重複 `Invoke` 開銷 (10-100x 加速)。 |
| 表達式樹編譯 | 用 `Expression.Lambda` 建立強型別委派,JIT 優化更好。 |
| Source Generators (C# 9+) | 編譯期產生程式碼替代執行期反射 (如 JSON 序列化、gRPC、DI 容器)。 |
| 只反射 Public/需要的成員 | `BindingFlags.Public | BindingFlags.Instance` 縮小搜尋範圍。 |
| 避免迴圈中 GetType() | 型別物件不可變,提取至迴圈外。 |
反射是 .NET **動態能力的基石**,賦予程式「自我認知」與「自我修改」的能力。掌握 `Assembly` → `Type` → `MemberInfo` → `Invoke/SetValue` 的操作鏈,並善用委派緩存、Source Generators 等現代優化手段,能構建極具擴充性的框架與工具。但請記住:**反射威力大、責任大**——僅在真正需要動態性時使用,靜態型別安全永遠是首選。