2012-11-19 22 views
33

例如C#如何分配列表<T>而不作爲參考?

List<string> name_list1 = new List<string>(); 
List<string> name_list2 = new List<string>(); 

在後面的代碼:

name_list1.Add("McDonald"); 
name_list1.Add("Harveys"); 
name_list1.Add("Wendys"); 

name_list2 = name_list1; // I make a copy of namelist1 to namelist2 

所以,從這個角度,我想不斷添加元素或進行中name_list2變化而不影響name_list1。我怎麼做?

回答

81
name_list2 = new List<string>(name_list1); 

這將克隆該列表。

+1

+1 - 口才好,我喜歡當'new'運營商這樣使用。 –

+0

這是一個不錯的,乾淨的解決方案。讓我來澄清一下,如果你這樣做,你就不用費心去用上面幾行的'new List ()'構造函數初始化name_list2,因爲你將創建一個對象來拋棄它。這不是一個大問題,而是一個糟糕的編碼習慣。 – adv12

+16

這仍然引用name_list1 – DoIt

7
name_list2 = new List<string>(name_list1); // Clone list into a different object 

此時,這兩個列表是不同的對象。您可以將項目添加到列表2而不會影響列表1

+1

「您可以添加項目到列表2而不影響列表1」,這是錯誤的。 – thinco

+0

這不適合我。它仍然是參考。我用這個來代替http://stackoverflow.com/a/25035202/1367450 –

+0

你可以在不影響list1的情況下添加和刪除frome list2,但是當你更新一個項目時它會在這兩個列表中傳播 –

4

問題是分配。在賦值name_list2 = name_list1;之前,變量name_list1name_list2指向的堆上有兩個不同的List對象。你填寫name_list1,這很好。但是這個任務說:「使name_list2指向堆的相同對象與name_list1。」 name_list2用來指向的列表不再可訪問並將被垃圾收集。你真正想要的是將內容name_list1複製到name_list2。你可以用List.AddRange來做到這一點。請注意,這將導致一個「淺」副本,這對你引用的例子來說很好,列表內容是字符串,但當列表成員是更復雜的對象時可能不是你想要的。這一切都取決於你的需求。

+0

這個答案解釋了發生了什麼比我迄今爲止讀過的其他人多,但我同意'name_list2 = new List (name_list1);'由他人提出的解決方案可能是實際執行復制的更簡潔的方法。 – adv12

3

另一個選項是:深克隆

public static T DeepCopy<T>(T item) 
     { 
      BinaryFormatter formatter = new BinaryFormatter(); 
      MemoryStream stream = new MemoryStream(); 
      formatter.Serialize(stream, item); 
      stream.Seek(0, SeekOrigin.Begin); 
      T result = (T)formatter.Deserialize(stream); 
      stream.Close(); 
      return result; 
     } 

所以,

你可以使用:

name_list2 = DeepCopy<List<string>>(name_list1); 

OR:

name_list2 = DeepCopy(name_list1); 

也會起作用。

+2

不錯的解決方案,但請記住,如果它是「引用類型」,那麼您總是需要在您的類上具有'Serializable'屬性。 –

+0

是的。您是對的。這是深刻克隆時最重要的一點。 – ayc

1

下面是一個替代的解決方案:

List<string> name_list1 = new List<string>(); 
    List<string> name_list2 = new List<string>(); 

    name_list1.Add("McDonald"); 
    name_list1.Add("Harveys"); 
    name_list1.Add("Wendys"); 

    name_list2.AddRange(name_list1.ToArray()); 

的ToArray的()方法拷貝 'name_list1' 到一個新的數組,這是我們然後添加通過的AddRange()方法來name_list2。

1

我喜歡這個LINQ ...

如果列表中的元素是原語或結構,然後...

L2 = L1.ToList() 

如果列表元素類,然後...

L2 = L1.Select(x => x.Copy()).ToList(); 

其中Copy可能只是MemberWiseClone的淺拷貝曝光,或者它可能是一些深層副本的實現。