首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 反射實戰:動態讀寫屬性/欄位、InvokeMember 多載綁定與效能優化指南

     編輯:關於C#

基礎:PropertyInfo / FieldInfo 讀寫


public class User { public int Id { get; set; } private string _name; public string Name { get=>_name; set=>_name=value; } }

var user = new User();
Type t = user.GetType(); // 或 typeof(User)

// 讀寫公開屬性
PropertyInfo pId = t.GetProperty("Id");
pId.SetValue(user, 101);
int id = (int)pId.GetValue(user);

// 讀寫私有欄位(需 BindingFlags)
FieldInfo fName = t.GetField("_name", BindingFlags.NonPublic | BindingFlags.Instance);
fName.SetValue(user, "Alice");
string name = (string)fName.GetValue(user);

進階:InvokeMember 一站式呼叫


// 簽章
object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args);

// 實例化(無參建構子)
object obj = t.InvokeMember(null, BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.Instance, null, null, null);

// 呼叫無回傳方法
t.InvokeMember("Display", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, obj, new[] { "Hello" });

// 呼叫有回傳方法
int result = (int)t.InvokeMember("Add", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, obj, new object[] { 1, 2 });

// 讀寫屬性
t.InvokeMember("Name", BindingFlags.SetProperty, null, obj, new[] { "Bob" });
string n = (string)t.InvokeMember("Name", BindingFlags.GetProperty, null, obj, null);

// 讀寫欄位
t.InvokeMember("_name", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance, null, obj, new[] { "Bob" });
string fn = (string)t.InvokeMember("_name", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance, null, obj, null);

BindingFlags 組合速查

旗標用途
Public | Instance預設,公開實例成員
NonPublic | Instance私有/受保護實例成員
Static靜態成員
FlattenHierarchy包含繼承鏈靜態成員
IgnoreCase名稱大小寫不敏感
DeclaredOnly僅本類別宣告,不含繼承

效能優化:Delegate.CreateDelegate 快取

反射每次呼叫約 100-500ns 開銷,高頻熱路徑請轉為委派:


// 靜態快取
static readonly Func GetId = (Func)Delegate.CreateDelegate(typeof(Func), typeof(User).GetProperty("Id").GetGetMethod());
static readonly Action SetId = (Action)Delegate.CreateDelegate(typeof(Action), typeof(User).GetProperty("Id").GetSetMethod());

// 使用
int id = GetId(user);
SetId(user, 202);

效能接近直接呼叫,且保持動態性。

.NET 5+ 新 API:源生成器 / Function Pointers

  • System.Reflection.Metadata 讀取編譯時中繼資料,避免執行時反射。
  • delegate* managed 函數指標(C# 9)可直接轉換方法指標,零配置。

最佳實踐清單

  1. 優先用強型別,反射只作為外掛/序列化/設定繫結等邊界層。
  2. 反射物件(PropertyInfo、MethodInfo)靜態快取,勿重複 GetProperty。
  3. 高頻路徑改用 Delegate.CreateDelegate 或原始碼生成器。
  4. 私有成員存取需 BindingFlags.NonPublic,注意信任層級限制(沙箱環境可能失效)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved