2013-04-25 94 views
0

所以我有一個列表,並在我的方法,我試圖返回一個新的列表與修改。修改爲新列表重複在原始列表

的問題是,雖然我作出的線索名單的Id的變化也正在向我傳遞的線索列表中進行。

 public List<Clue> NewOrderList(List<Clue> clues, int[] ids) 
    { 
     var newClueOrder = new List<Clue>(); 

     // For each ID in the given order 
     for (var i = 0; i < ids.Length; i++) 
     { 
      // Get the original clue that matches the given ID 
      var clue = clues.First(clue1 => clue1.Id == ids[i]); 

      // Add the clue to the new list. 
      newClueOrder.Add(clue); 

      // Retain the ID of the clue 
      newClueOrder[i].Id = clues[newClueOrder.Count - 1].Id; 
     } 

     return newClueOrder; 
    } 

這是爲什麼,什麼是這是最好的解決方案嗎?我見過類似的問題,但說實話,我並不十分明白解決方案到底是什麼。

+1

喬恩Skeet給出了一個真正的好討論這個,爲什麼/當它發生在這裏 - http://www.yoda.arachsys.com/csharp/parameters.html – Tim 2013-04-25 01:09:01

+0

列表是通過引用。如果你想要一個新的對象(線索)創建一個副本。 – 2013-04-25 01:09:41

+0

什麼和哪裏是最好的地方來創建它的副本? – 2013-04-25 01:09:45

回答

1

這是因爲Clue是一個參考類型。您並未創建新的Clue實例,您實際上正在更改現有實例。

要解決這個問題,你需要使用一個拷貝構造函數或某種克隆得到了深刻的副本:

 // Get the original clue that matches the given ID 
     var clue = clues.First(clue1 => clue1.Id == ids[i]); 

     // Copy constructor 
     var newClue = new Clue(clue); 

     // Or, use cloning 
     var newClue = clue.Clone(); 

     // Add the clue to the new list. 
     newClueOrder.Add(newClue); 

     // Retain the ID of the clue 
     newClueOrder[i].Id = clues[newClueOrder.Count - 1].Id; 

Clone()或拷貝構造函數,你需要做副本所有其他非不可變參考類型,不要只重新分配參考。例如,假設線索有:

public class Clue 
{ 
    ... 

    public Clue Clone() 
    { 
     Clue newClue = new Clue(); 
     newClue.SomeClassType = this.SomeClassType.Clone(); // You'll need to get a clone or copy of all non-immutable class members as well. 
     newClue.Id = this.Id; // Value types are copied by value, so are safe to assign directly. 
     newClue.Name = this.Name; //If Name is a string, then this is safe too, since they are immutable. 
     return newClue; 
    } 
} 
+0

因此,當我添加線索newClueOrder列表時,是否添加newClue(您的示例顯示正在添加的原始線索)? – 2013-04-25 01:54:48

+0

另外,我不明白你的例子克隆線索。我是否創建一個方法克隆,它返回一個克隆的線索。此方法是否接受線索作爲參數?在你的例子中,你創建了一個新的線索並製作所有類型的副本......但是你展示了newClue引用它自己?這是一個錯誤? – 2013-04-25 02:00:38

+0

第一條評論 - 是的,這就是我的意思。我編輯糾正。第二條評論 - 是的,你在Clue類上創建了一個Clone()方法。 newClue不引用它自己。 'this'限定符指的是您正在使用的現有實例來創建初始化/創建newClue實例。 – Gjeltema 2013-04-25 02:02:48

2

您創建一個淺拷貝。這聽起來像你想要一份清單的深層副本。所以,我會先創建一個深層副本,然後修改需要修改的任何內容並返回新列表。

可以序列和desirialize列表中,當你創建列表的深層副本要創建新的線索對象,而不是隻是在一個淺拷貝引用他們喜歡創造一個深拷貝

public List<Clue> NewOrderList(List<Clue> clues) 
    { 
     List<Clue> newstringOrder = CreateDeepCopy(clues); 

     // Add code to modify list 

     return newstringOrder; 
    } 


public List<Clue> CreateDeepCopy(List<Clue> c) 
{ 
    //Serialization  
    if(c == null) 
      return null; 
    BinaryFormatter bf = new BinaryFormatter(); 
    MemoryStream ms = new MemoryStream(); 
    bf.Serialize(ms, c); 

    //Deserialization    
    ms.Position = 0;   
    List<Clue> list = (List<Clue>)bf.Deserialize(ms);  

    return list;  

} 
+0

如何以及在哪裏創建深層副本並對其進行序列化/反序列化? – 2013-04-25 01:17:00

+0

您可以通過序列化/取消序列化原始列表來創建深層副本。當你對列表進行desirial化時,你所擁有的是一個原始版本的深層副本 – Flavia 2013-04-25 01:19:02

+0

你能提供一個例子嗎?我不確定我是否曾經序列化過或列出了一個列表,但我不知道該怎麼做。 – 2013-04-25 01:20:52