.NET 反射 (System.Reflection) 讓程式在執行時檢查、操作未知類型,打破靜態編譯的限制。本文從基礎類別對應、檢查與調用、動態平均值計算實例,延伸至序列化場景的效能優化:結合 CodeDom 動態產生強型別協助類,將反射開銷從「每實例」降為「每類型一次」。
| 運行時概念 | System.Reflection 類別 |
|---|---|
| 組件 | Assembly |
| 模組 | Module |
| 類型 | Type |
| 方法 | MethodInfo |
| 建構函式 | ConstructorInfo |
| 屬性 | PropertyInfo |
| 欄位 | FieldInfo |
| 事件 | EventInfo |
所有成員資訊類別繼承自 MemberInfo,方法與建構函式共同繼承 MethodBase。
Type t = myObject.GetType();
foreach (MethodInfo m in t.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public))
Console.WriteLine(m.Name); // 僅列出該類別宣告的公用實例方法
BindingFlags 組合精確控制搜尋範圍:Instance/Static、Public/NonPublic、DeclaredOnly (排除繼承)、FlattenHierarchy。
Type t = typeof(MyClass);
MethodInfo method = t.GetMethod("MyMethod2");
object[] args = { 42 };
method.Invoke(instance, args); // 等同 instance.MyMethod2(42)
關鍵特性:MethodInfo 可**脫離原始實例**綁定至**相同類型**的另一實例調用,實現「方法與實例分離」的後期繫結。
public static int ComputeAverage(IEnumerable<object> objs, string methodName) {
MethodInfo method = null;
Type knownType = null;
int sum = 0, count = 0;
foreach (var obj in objs) {
if (method == null) {
knownType = obj.GetType();
method = knownType.GetMethod(methodName);
}
// 關鍵限制:MethodInfo 僅能用於 knownType 或其衍生類別實例
sum += (int)method.Invoke(obj, null);
count++;
}
return count == 0 ? 0 : sum / count;
}
陷阱:若集合包含實作同名方法但**無共同基類**的類型 (如 EnemyOfIntReturner),Invoke 會拋出 TargetException。解決:快取每個具體類型的 MethodInfo,或捕獲例外後重新取得。
單純反射序列化每個實例都需完整類型分析,開銷大。優化策略:
Type.GetProperties() 取得結構描述CodeDom 產生針對該類型的強型別 SerializerHelper 類別,直接存取屬性 (如 obj.Name)CodeDomProvider.CompileAssemblyFromSource 產生記憶體組件public class SimpleSerializer {
private readonly object _helperInstance; // 動態生成的 Helper 實例
private readonly MethodInfo _serializeMethod;
public SimpleSerializer(Type dataType) {
// 1. 反射分析 dataType 結構
// 2. CodeDom 生成 Helper 類別原始碼
// 3. 編譯組件、建立實例、取得序列化方法
}
public void Serialize(object input, SimpleDataWriter writer) {
_serializeMethod.Invoke(_helperInstance, new[] { input, writer });
}
}
後續同類型實例直接呼叫強型別 Helper,**零反射開銷**。
XmlSerializer (內建優化)、System.Text.Json (高效能)、Expression Tree (較 CodeDom 輕量)、Roslyn Source Generator (編譯時產生)