2010-07-17 67 views
4

我一直在玩弄徹底理解參考和值類型。就在我以爲有了它時,我碰到了這個場景......參考和值類型場景

我創建了一個包含單個對象的類。

class Container 
{ 
    public object A {get; set;} 
} 

當我創建這個Container類的實例(a)時,我創建了一個引用類型的實例。我爲該類中的對象分配一個整數。據我所知,這將作爲另一個參考類型的對象裝箱。

int start = 1; 
Container a = new Container{ A=start }; 

我創建容器類(B)的另一個實例,但將第一個容器到它的值,b的值現在是一個參考。

Container b = a; 

正如我打印出a.A和b.A的值一樣,它們是相同的。

Console.WriteLine("a.A={0},b.A={1}",a.A,b.A); 
//a.A=1,b.A=1 

而且,正如所料,當我改變A.A的價值b.A的價值也會發生變化,由於它們引用同一個對象。

a.A = 2; 

Console.WriteLine("a.A={0},b.A={1}",a.A,b.A); 
// a.A=2,b.A=2 

現在我決定嘗試使用單個本地對象。再次,我將整數放入第一個對象中,並將第一個對象的值分配給第二個對象。我相信這個對象應該是一個引用類型,所以c和d應該引用同一個對象。不改變任何東西,它們會返回相同的值。

int start = 1; 
object c = start; 
object d = c; 

Console.WriteLine("c={0},d={1}",c,d); 
// c=1,d=1 

像以前一樣,當改變初始對象的值時,我期望兩個對象的值是相同的。

c = 2; 

Console.WriteLine("c={0},d={1}",c,d); 
// c=2,d=1 

當我打印這兩個對象的結果時,d的值不會像以前那樣改變。

有人可以解釋爲什麼在這種情況下,作業與以前不同嗎?

感謝

回答

10

這是你的第一個錯誤:

我創建容器類(B)的另一個實例,但將第一個 容器將它的值,b的值現在是對...的引用。

Container b = a; 

創建另一個實例。它宣佈另一個變量。現在這兩個變量都指向同一個對象。

(我會繼續閱讀時繼續編輯此答案...)

接下來:

int start = 1; 
object c = start; 
object d = c; 
Console.WriteLine("c={0},d={1}",c,d); // c=1,d=1 

像以前一樣,改變初始對象的值的情況下,我期望 兩個對象的值是相同的。

c = 2; 
Console.WriteLine("c={0},d={1}",c,d); // c=2,d=1 

那不是改變對象它改變變量。每個作業都複製一個值 - 除了其中一個還執行裝箱操作。讓我們稍微簡化一下:

object c = "first string"; 
object d = c; 

現在沒有涉及拳擊 - 它只會讓它更容易理解。

兩者變量當前具有指向相同對象的值。這是由於任務,但沒有別的鏈接這兩個變量。他們碰巧具有相同的價值,但他們是自變量。現在,讓我們改變一個:

c = "different string"; 

這種情況已經改變的c值是指不同的對象。如果您打印出cd的值,它們將分別爲「不同的字符串」和「第一個字符串」。 更改c的值不會更改d的值。


現在,讓我們回到以前的場景,看看爲什麼它不同。在那裏,你有:

a.A = 2; 

這根本不會改變a的值。它正在改變對象a中的數據。

讓我們使用現實世界的比喻來使這更容易。假設我們所有的變量都是寫有房屋地址的紙片。 a.A = 2;的變化就像改變該地址處房屋的內容。當然,其他地址寫在上的同一個地址的紙將會看到變化。

現在想想你的c/d方案。再次,假設我們有兩張紙,並且由於賦值運算符,它們都寫有相同的地址。現在,您爲c變量本身分配新值就像清理c紙上的地址並在其上寫入不同的地址。這根本不會改變d紙 - 它仍然有舊地址,如果你訪問那所房子,你會發現沒有什麼改變。這是只是寫在更改的那張紙上。

這有幫助嗎?

2

在第一個例子中,你有這樣的:

a  b 
    \ / 
    \/ 
    | | 
    v v 
(Container) 

只有一個在這裏容器實例。這兩個變量都有對這個容器的引用。當你改變容器時,兩個變量都會看到變化。

然而,在這種代碼:

object c = 1; 
object d = c; 

第二分配並不意味着「d是對C的別名」,它只是意味着第二分配cd指向相同的對象之後。

c = 2; 

現在重新分配c到一個新的盒裝整數所以cd現在指向兩個不同的對象。這兩個對象沒有任何關係。

Before     After 

c  d    c     d 
    \ /  c=2 |     | 
    \/  ----> |     | 
    | |     |     | 
    v v     v     v 
(boxed integer 1)  (boxed integer 2) (boxed integer 1) 
0

在你的第一個場景中,你有一個對堆上的一個對象的引用。你有兩個變量(「a」,「b」)指向這個同一個對象。這就是爲什麼當你改變這個對象的成員時,你會看到它反映在兩個變量上。

在你的第二種情況下,你正在做一些完全不同的事情。當你這樣做:

c = 2 

你實際上創建了一個全新的對象。 int的值類型被轉換爲一個對象,所以創建了一個新的引用對象。此時,您的「d」變量不再與您的「c」變量指向相同的對象。

3

區別在於封裝對象Container

在第一種情況下,您有一個包含引用的對象。當你說你創建了一個Container類的新實例時,你沒有。您只是將引用複製到現有對象。由於您有兩個對同一個對象的引用,您可以通過一個引用更改對象的內容並通過另一個引用讀取它。

a  b   a  b 
    \ /   \ /
    \/   \/
---------  --------- 
|  |  |  | 
| A |  | A | 
| | |  | | | 
----|---- -> ----|---- 
    |    | 
---------  --------- 
|  |  |  | 
| 1 |  | 2 | 
|  |  |  | 
---------  --------- 

在第二種情況下,你也有兩個引用兩個相同的對象,但在這種情況下,你直接引用的是盒裝的對象,而不是一個容器。當您爲其中一個參考指定一個新值時,您會得到兩個單獨的對象。一個對象是boxed 1,另一個對象是boxed 2.當給b賦一個新值時,它不會將值放入它指向的框中,它將創建一個包含新值的新盒裝對象。

a  b    a   b 
    \ /   |   | 
    \/    |   | 
--------- -> --------- --------- 
|  |  |  | |  | 
| 1 |  | 1 | | 2 | 
|  |  |  | |  | 
---------  --------- ---------