C# 類繼承中的私有欄位都去了哪裡?

来源:https://www.cnblogs.com/huangxincheng/archive/2022/06/04/16341267.html
-Advertisement-
Play Games

最近在看 C++ 類繼承中的欄位記憶體佈局,我就很好奇 C# 中的繼承鏈那些 private 欄位都哪裡去了? 在記憶體中是如何佈局的,畢竟在子類中是無法訪問的。 一:舉例說明 為了方便講述,先上一個例子: internal class Program { static void Main(string ...


最近在看 C++ 類繼承中的欄位記憶體佈局,我就很好奇 C# 中的繼承鏈那些 private 欄位都哪裡去了? 在記憶體中是如何佈局的,畢竟在子類中是無法訪問的。

一:舉例說明

為了方便講述,先上一個例子:


    internal class Program
    {
        static void Main(string[] args)
        {
            Chinese chinese = new Chinese();

            int num = chinese.b;   //b 欄位無法訪問,編譯報錯

            Console.WriteLine(num);
        }
    }

    public class Person
    {
        public int a = 10;
        private int b = 11;
    }

    public class Chinese : Person
    {
        public int c = 12;
    }

根據 C# 的類繼承原則,上面的 chinese.b 寫法肯定是無法被編譯的,因為它屬於父類的 私有欄位,既然無法被訪問,那這個 private b 到底去了哪裡呢? 要想找到答案,只能先從 chinese 實例處的彙編代碼看起,看看有沒有什麼意外收穫。

二:查看 chinese 處彙編代碼

new chinese() 處下一個斷點,查看 Visual Stduio 2022 的反彙編視窗。

接下來我稍微解讀下:

1. 根據 MT 類型 實例化 chinese


07FD6176  mov         ecx,87205C4h  
07FD617B  call        CORINFO_HELP_NEWSFAST (06E30C0h) 

這裡的 87205C4h 就是 Chinese 類型的 MT,然後通過 CLR 下的 CORINFO_HELP_NEWSFAST 處的方法進行實例化。

2. 使用 chinese 的構造函數進行類初始化


07FD6180  mov         dword ptr [ebp-40h],eax  
07FD6183  mov         ecx,dword ptr [ebp-40h]  
07FD6186  call        CLRStub[MethodDescPrestub]@7e34871e07fd5d20 (07FD5D20h)
07FD618B  mov         eax,dword ptr [ebp-40h] 

這裡的 eax 是 CORINFO_HELP_NEWSFAST 初始化方法的返回值,可以在 ecx,dword ptr [ebp-40h] 處下一個斷點,觀察它的記憶體佈局。

從佈局圖看,此時的 chinese 只是一個清零的預設狀態,此時的 a,b,c 三個欄位還沒有被賦值,那什麼時候被賦值呢? 這就是構造函數要做的事情了,也就是上面的 CLRStub[MethodDescPrestub]@7e34871e07fd5d20 (07FD5D20h) 指令,接下來在 07FD618B 處下一個斷點,再次觀察 0x02C9F528 處的記憶體地址,也就是 ebp-40 的位置,接下來我們繼續執行,截圖如下:

從圖中可以看到,當構造函數執行完之後,有三處記憶體地址(變紅)被賦值了,依次是 a,b,c,這時候是不是讓人眼前一亮。

3. 洞察真相

原來那個 b=11 並沒有丟,而是被 chinese 類給完全繼承下來的,而且佈局規則是 父類 欄位在前, 子類 欄位在後的一種方式,有點意思,接下來的問題是如何把它提取出來?

三:如何提取 b 欄位

如果是 C 語言,我們用 *(pointer+2) 就可以輕鬆提取,那用托管的 C# 如何去實現呢? 可以用複雜的 Marshal 包裝類,應該也可以變相的使用 Span 去搞定,這裡我就不麻煩了,直接用非安全代碼下的 指針 去擺平,在 a 欄位偏移 +4 的位置上提取, 參考代碼如下:


        static void Main(string[] args)
        {
            unsafe
            {
                Chinese chinese = new Chinese();

                fixed (int* ch = &chinese.a)
                {
                    int b = *(ch + 1);

                    Console.WriteLine($"b={b}");
                }
            }
        }
    }

哈哈,是不是挺有意思。

圖片名稱
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • vscode 中配置Java環境 轉載說明:本篇文檔原作者[@火星動力猿],文檔出處來自嗶哩嗶哩-【教程】VScode中配置Java運行環境 轉載請在開頭或顯眼位置標註轉載信息。 1.下載VScode 官網地址:https://code.visualstudio.com/ (點鏈接時按下Ctrl,不 ...
  • SpringMVC 是基於 MVC 開發模式的框架,用來優化控制器,是 Spring 家族的一員,同時它也具備 IOC 和 AOP ...
  • 一、填空題 在種群增長預測問題中,若資源環境等因素是有限的,則應使用的微分方程模型為 Logistic模型 某種群分為 4 個年齡組, 各組的繁殖率分別為 0, 0.8, 1.8, 0.2, 存活率分別為 0.5, 0.7, 0.9, 0. 現各組的數量均為 100, 則該種群的的穩定分佈向量為 解 ...
  • 一、Postman Postman 是一個款 HTTP 請求模擬工具 首先演示一下 Postman 最基本的使用,創建一個 Spring Boot 項目,測試的代碼如下: import org.springframework.web.bind.annotation.GetMapping; impor ...
  • ## 進程與線程的區別 - 進程基本上相互獨立的,而線程存在於進程內,是進程的一個子集 - 進程擁有共用的資源,如記憶體空間等,供其內部的線程共用 - 進程間通信較為複雜 - 同一臺電腦的進程通信稱為 IPC(Inter-process communication) - 不同電腦之間的進程... ...
  • 哈工大軟體構造Lab2中Assert的使用總結,可供後來學子借鑒學習 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • 這是一個類似於記事本的文字處理器。與正常的記事本不同的是,它會將文本文檔進行加密,確保無法被常規的程式打開。 由於本人是一位業餘編程愛好者,對於“python之禪”之類的規則比較不以為然,因此本程式代碼也許有些許凌亂(當然不利於後期修改)。 這篇文章我早已發佈過,但當時只給出了代碼,並加了一些註釋。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...