2012-01-11 95 views
7

引用類型和值類型之間的差異通常會讓初學者感到困惑,因爲不瞭解值類型的變量實際上是什麼。我們知道:引用類型 - 我們可以看到實際的引用嗎?

  • 值類型存儲實際
  • 引用類型只有參考存儲對象

是否可以檢查每一個類型的變量,要麼看該值,還是實際參考本身?參考是否存儲爲某種編碼值?我知道引用可以通過值傳遞,所以我假設如此。

我認爲這將有助於新人的理解,並且非常有趣的探索。

+1

你只會看到一個地址,一個看似隨機的數字。你爲什麼想看到這個? – Dykam 2012-01-11 12:24:43

+3

鞏固變量內部不是他們設定的對象的想法,而是一個地址。我們如何訪問這個? – 2012-01-11 12:25:32

+1

http://stackoverflow.com/questions/1978232/how-can-i-display-the-actual-value-of-a-reference-in-c-sharp – 2012-01-11 12:33:18

回答

10

是否可以檢查每種變量以查看值或實際引用本身?

只是爲了澄清,引用類型變量的的參考。參考是價值。

引用是一種值,就像int是一種值。與int不同,參考值只能是複製取消引用;你不能直接在C#中觀察它的值,因爲它的值是垃圾收集器的實現細節。

是否將參考存儲爲某種編碼值?

是的,正好。在實踐中,一個引用是一個32或64位整數(取決於你是在一個32位還是64位的進程中),這個指針指向垃圾收集器已知的一些結構的指針,與被引用對象的數據相關聯。

如果您想直接查看引用,那麼執行此操作的工具就是調試器。將C#代碼加載到調試器中,編譯它,運行它,找到一個斷點,並查看堆棧和寄存器的狀態。有一點聰明,你應該能夠找出哪些堆棧位置和寄存器對應於哪些局部變量。與值類型的局部變量相對應的位置將包含這些值;那些引用類型將包含看起來像指針的值。如果您檢查內存窗口中的這些指針,您將查看由垃圾回收器維護的用於描述對象內容的結構。

+3

我認爲重要的是要注意,雖然現有的.net實現可能會將地址(對象信息記錄的地址)存儲在引用變量中,但不能保證將來的版本可以這樣做。例如,有可能參考變量的某些位是選擇多個堆中的一個的索引,而其他位是該堆中的索引。雖然這樣的系統對於現有的處理器可能效率低下,但圍繞這種模型設計未來的處理器可能允許更高效的高速緩存利用。現有的.net代碼不應該關心這些細節。 – supercat 2012-01-11 17:06:55

+0

@supercat:絕對。實際上,引用可以被實現爲完全不透明的句柄,它們只是索引到垃圾收集器擁有的某個表中才有意義;沒有理由爲什麼參考文獻中的任何位需要具有特定的含義。碰巧,在今天的實現中,引用*的每一位都是有意義的,因爲它可以被解釋爲一個指針。但是這隨時都可能發生變化。 – 2012-01-11 17:12:21

+0

出於好奇,雖然現有的CPU可能不會讓這些事情變得非常有效,但我想知道在未來的CPU中,對於數據量爲8(可能是16)個字節或更少的對象有一個小對象堆是否值得,對象表中的每個插槽將保存實際的對象數據,而不是指向它的指針。在現有的CPU上,每個堆訪問都需要額外的指令來確定哪個堆是給定的引用所屬的,但是如果有一個「獲取對象地址」指令,它在引用中用一點來選擇單向或雙向間接... – supercat 2012-01-11 17:30:36

1

你可以很容易地用固定的物體做到這一點;

GCHandle gch=GCHandle.Alloc(data, GCHandleType.Pinned); 
IntPtr AddressInMemory=gch.AddrOfPinnedObject(); 
+0

與[幾乎所有類一樣,這對[不可擦]類型(http://msdn.microsoft.com/zh-cn/library/75dwhxf7.aspx)不起作用。 – svick 2012-01-11 12:39:08

+0

我站好了。看起來像我唯一需要的是與原始人在一起。 – 2012-01-11 12:45:33

1

你可以用unsafe代碼做到這一點:

unsafe 
    static void Main(string[] args) 
    { 
     string s = "Hello"; 

     fixed (char* pc = s) 
     {     
      IntPtr p = (IntPtr)pc; 
      Console.WriteLine(p); // here is your meaningless address 
     }    
    } 
+0

這使得s的固定副本,所以你爲什麼不直接pin s? – 2012-01-11 12:38:24

+0

我們不會用's'來做任何事情。 – 2012-01-11 12:39:27

+0

@EugenRieck您是否有該陳述的來源?我看不到在這裏複製。 – CodesInChaos 2012-01-11 12:41:39

5

這可能是一個喬恩斯基特,但我可能有一個不同的角度:

不要擔心如何這些東西在內存中表示。除非您已經閱讀了整個語言規範 - 無論如何,誰還這樣做? - 你並不需要知道。真。不要費心記憶哪些數據存儲在哪裏 - 很可能這是特定於實現的。

相反,用語義來思考,例如,傳遞給函數的值類型是複製,而引用類型是引用。像這樣的東西。

你並不真正想知道一個類型的聲明實際上是什麼。相信我。你想知道的是它是如何表現的

+2

+1這裏是Eric Lippert說的(http://blogs.msdn.com/b/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx)同樣的東西。地址是實現細節,語言規範在指定引用時沒有提及地址。瞭解他們的行爲方式,而不是他們的工作方式。 – MarkJ 2012-01-11 12:51:31

+2

雖然我同意你的發言,但我覺得這不是問題的關鍵。我想他想知道如何去做 - 而不是你的意見,爲什麼它不重要。瞭解複雜功能的運作方式可以使您成爲更好的工程師,即使您沒有找到即時使用該知識的工具。 – 2012-01-11 13:16:10

+0

雖然我都非常感謝並且同意你的回答,但並沒有解決我的問題。我只想訪問地址**只是爲了證明它在那裏**沒有其他原因。我同意@ AdamG.Carstensen。 – 2012-01-11 13:40:19

相關問題