2010-06-30 69 views
2

將對象添加到List等集合時會發生什麼?C#List <T>內部結構

List<Person> people = new List<Person>(); 
Person dan = new Person() { Name="daniel", Age=10 }; 
people.Add(dan); 
dan = new Person() { Name = "hw", Age = 44 }; 

當我執行上面的代碼時,List<Person> people不會受到最後一行的影響。 所以我假設列表副本引用的添加對象,所以當更改引用時,列表不會受到影響。我對麼?

+1

你在哪裏添加一個對象列表?你能修復你的代碼嗎? – Arseny 2010-06-30 08:51:07

+0

哎呀!忘了添加一個對象。謝天謝地,stackoverflow的聰明頭腦理解了我想傳達的內容。 – Yeonho 2010-06-30 14:01:01

回答

5

那麼,你顯示的代碼實際上並沒有增加任何東西到列表中。我假設你的意思是:

people.Add(dan); 

在那裏的某個地方?

但是,是的,List<T>包含對象的引用。它不知道參考文獻的來源。值得清楚的是變量和它的價值之間的區別。當您打電話:

people.Add(dan); 

該拷貝在這種情況下作爲參數的內List<T>.Add初始值參數表達式(dan)的值。該值僅僅是一個參考 - 它與dan變量沒有關係,除了恰好是調用List<T>.Add時變量的值。

這是完全一樣的以下情況:

Person p1 = new Person { Name = "Jon" }; 
p2 = p1; 
p1 = new Person { Name = "Dan" }; 

這裏,p2價值仍然將是一個名爲「喬恩」的人一個參考 - 第二行只是複製的p1值到p2而不是將兩個變量關聯在一起。一旦理解了這一點,就可以將相同的邏輯應用於方法參數。

+0

在你給出的p1和p2例子中,Person「Jon」繼續存在的唯一原因是因爲p2 = p1賦值,是正確的嗎?如果那項任務不在那裏,那麼創建「丹」如果我是正確的話,GC會消滅「喬恩」的實例嗎?謝謝。 – Sabuncu 2012-01-17 15:18:13

+1

@Sabuncu:呃,這不是真正的「丹」的創造,「消滅」另一個 - 這是事實,將沒有更多的引用,以保持另一個對象的活着。 (當另一個人被收集時,沒有什麼可說的*,請注意你。)值得從GC方面分離創建另一個對象。例如,它不像一個替換另一個。 – 2012-01-17 15:33:16

+0

謝謝!是一個簡單的問題,但我知道來自你的答案是一個學習經驗。 – Sabuncu 2012-01-17 15:47:06

4

以及代碼List<Person> people不應該受到第二行的影響。

反正List<Person>得到一個參考,如果您使用.Add()所以如果你修改這個人後,人在列表中「修飾」過(這是同一個人),但如果你指定的人給別人你'不影響參考,您將符號分配給新的參考。

如:

List<Person> people = new List<Person>(); 
Person dan = new Person() { Name="daniel", Age=10 }; 
people.Add(dan); 

/* DanData = { Name="daniel", Age=10 }; 
* `people[0]` maps to "DanData" 
* `dan` maps to "DanData" */ 

dan.Name = "daniel the first"; 
string dansNameInList = people[0].Name; /* equals "daniel the first" */ 

/* DanData = { Name="daniel the first", Age=10 }; 
* `people[0]` maps to "DanData" 
* `dan` maps to "DanData" */ 

people[0].Name = "daniel again"; 
string dansName = dan.Name /* equals "daniel again" */ 

/* DanData = { Name="daniel again", Age=10 }; 
* `people[0]` maps to "DanData" 
* `dan` maps to "DanData" */ 

dan = new Person() { Name = "hw", Age = 44 }; 
string dansNameInListAfterChange = people[0].Name /* equals "daniel again" */ 
string dansNameAfterChange = dan.Name /* equals "hw" */ 

/* DanData = { Name="daniel again", Age=10 }; 
* NewData = { Name = "hw", Age = 44 }; 
* `people[0]` maps to "DanData" 
* `dan` maps to "NewData" */ 
1

要回答原來的問題,假設你打算叫第三行之前的人添加到列表中:

是,列表僅存儲對象的引用。在C#中,全部對象變量是引用。

因此,當您第二次致電new Person()時,由變量dan持有的參考值將更新爲指向新實例。如果第一個實例沒有指向它的引用,它將在下一輪垃圾回收。如果您已將第一個實例添加到列表中,則該列表仍將保留它對第一個實例的引用。

0

添加你的代碼

people[0] = dan; 

年底將指向新丹對象。

0

在.NET編程中重要的是要很好地理解引用類型和值類型之間的區別。本文提供了一個很好的概述: http://www.albahari.com/valuevsreftypes.aspx

在這種情況下,您創建了兩個Person對象(Daniel,age 10和hw,年齡44)。這是引用造成混淆的兩個對象的變量。


Person dan = new Person() { Name="daniel", Age=10 }; 

在這裏,一個局部變量,丹,被分配給新創建的(丹尼爾,年齡10)的參考對象。


people.Add(dan); 

這裏,屬性人[0]是(經由List.Add方法間接地)分配給現有的(丹尼爾,年齡10)的對象的引用。


dan = new Person() { Name = "hw", Age = 44 }; 

這裏,本地變量,丹,被分配給新創建的(HW,年齡44)的參考對象。但財產人[0]仍然認爲現存的(丹尼爾,10歲)對象。