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

高效存取非公用欄位與屬性:NonPublicPropertyProxy 元件深度解析

     編輯:關於ASP.NET

在 .NET 中存取私有/內部欄位與屬性,傳統反射雖通用但效能低落。NonPublicPropertyProxy 採用動態 IL 代理技術,效能較反射提升 3-4 個數量級,且支援實例/靜態欄位、實例屬性的讀寫,是高效能框架開發的利器。

為何需要此元件?

  • DynamicMethodProxyFactory 僅支援方法呼叫,屬性雖可透過 get/set 方法存取,但欄位無對應方法,仍需反射
  • ORM、序列化、物件映射、測試框架頻繁需存取非公用成員
  • 效能敏感場景(如大量資料映射)反射開銷不可接受

核心特性

功能支援備註
實例屬性讀寫✅透過 get/set 方法代理
實例欄位讀寫✅直接 IL 存取欄位位址
靜態欄位讀寫✅傳入 null 作為 instance
靜態屬性讀寫❌需改用 DynamicMethodProxyFactory

使用示範

public class User
{
    private string _name;
    private int _id;
    private UserStatus _status;
    private List _children;
    private static int _staticValue;

    // 僅為測試用,實際專案中無公用 setter
    public string Name => _name;
    public int Id => _id;
}

var user = new User();

// 取得 Setter 代理(首次呼叫會產生 IL,後續複用極快)
var nameSetter = NonPublicPropertyProxyFactory.GetPropertySetter(typeof(User), "name");
var idSetter = NonPublicPropertyProxyFactory.GetPropertySetter(typeof(User), "id");
var statusSetter = NonPublicPropertyProxyFactory.GetPropertySetter(typeof(User), "status");
var childrenSetter = NonPublicPropertyProxyFactory.GetPropertySetter(typeof(User), "Children");
var staticSetter = NonPublicPropertyProxyFactory.GetPropertySetter(typeof(User), "staticValue");

// 呼叫代理委派
nameSetter(user, "Abu");
idSetter(user, 995006);
statusSetter(user, UserStatus.Admin);
childrenSetter(user, new List { "Child1", "Child2" });
staticSetter(null, 100); // 靜態欄位傳入 null

效能基準參考

// 100 萬次迴圈測試 (Release, x64)
Reflection SetValue:     ~1,200 ms
DynamicMethodProxy:      ~0.3 ms   (快 4000 倍)
NonPublicPropertyProxy:  ~0.4 ms   (快 3000 倍)

適用場景與注意事項

場景建議
單次/低頻存取 直接用反射,避免 IL 產生一次性開銷
ORM 實體映射 ✅ 最佳選擇,啟動時快取代理,運行期極速
序列化/反序列化 ✅ 大量物件圖處理效能顯著提升
單元測試私有狀態驗證 ✅ 替代 PrivateObject,語法更簡潔

原理解析

  1. 透過 DynamicMethod 產生強型別存取委派
  2. IL 直接對欄位位址進行 ldfld/stfld 或屬性 call get/set 方法
  3. 委派簽名統一為 Action<TInstance, TValue> (Setter) / Func<TInstance, TValue> (Getter)
  4. 工廠方法內部以 Dictionary<Type, Dictionary<string, Delegate>> 快取,確保單一型別/成員僅編譯一次

原始碼來源

本元件萃取自 NBear.Mapping 專案的屬性存取邏輯,經重構獨立發布。完整原始碼可參考 GitHub 專案,包含單元測試與效能基準專案。

掌握動態 IL 代理技術,能在框架開發、高效能資料處理、測試自動化等領域脫離反射束縛,實現極致效能與優雅 API 的雙重保障。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved