拆箱是否只返回一個指向堆上裝箱對象內的值的指針?
在這篇 MSDN 雜誌文章中,作者指出(強調我的):
請注意,裝箱始終會創建一個新對象並將未裝箱值的位複製到該對象。**另一方面,拆箱只是返回一個指向裝箱對像中數據的指針:不會發生記憶體複製。**但是,通常情況下,您的程式碼將導致未裝箱引用指向的數據無論如何都被複製。
我對我加粗的句子及其後面的句子感到困惑。從我讀過的所有其他內容中,包括這個 MSDN page,我以前從未聽說過拆箱只會返回一個指向堆上值的指針。我的印像是拆箱會導致您擁有一個包含堆棧上值副本的變數,就像您開始時一樣。畢竟,如果我的變數包含“指向堆上值的指針”,那麼我沒有值類型,我有一個指針。
有人可以解釋這是什麼意思嗎?作者是在破解嗎?(文章中至少還有一個明顯的錯誤)。如果這是真的,“您的程式碼將導致未裝箱引用指向的數據無論如何都被複製”的情況是什麼?
我剛剛注意到這篇文章已經有將近 10 年的歷史了,所以這可能是 .Net 生命早期發生的變化。
文章是準確的。然而,它談論的是真正發生的事情,而不是編譯器生成的 IL 的樣子。畢竟,.NET 程序從不執行 IL,它執行由 JIT 編譯器從 IL 生成的機器程式碼。
拆箱操作碼確實會生成程式碼,該程式碼會生成指向堆上表示值類型值的位的指針。JIT 生成對 CLR 中名為“JIT_Unbox”的小幫助函式的呼叫。clr\src\vm\jithelpers.cpp 如果你有 SSCLI20 原始碼。Object::GetData() 函式返回指針。
從那裡,最常見的值首先被複製到 CPU 寄存器中。然後可能會儲存在某個地方。它不一定是堆棧,它可以是引用類型對象(gc 堆)的成員。或者一個靜態變數(載入器堆)。或者它可以被壓入堆棧(方法呼叫)。或者,在表達式中使用值時,可以按原樣使用 CPU 寄存器。
調試時,右鍵點擊編輯器視窗並選擇“Go To Disassembly”以查看機器程式碼。