对新列表的修改在原始列表中重复

时间:2013-04-25 01:06:30

标签: c# .net

所以我有一个列表,在我的方法中,我试图返回一个带有修改的新列表。

问题是,我对线索列表的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;
    }

为什么会这样,最好的解决办法是什么?我见过类似的问题,但说实话,我不太明白解决方案到底是什么。

2 个答案:

答案 0 :(得分:2)

你创建一个浅拷贝。听起来你想要一份列表的深层副本。因此,我首先创建一个深层副本,然后修改您需要修改的内容并返回新列表。

您可以序列化和绝望化列表以创建深层副本

当您创建列表的深层副本时,您正在创建新的线索对象,而不仅仅是像浅层副本那样引用它们

   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;    

}

答案 1 :(得分: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()或复制构造函数中,您需要复制所有其他非不可变引用类型,不要只重新分配引用。例如,假设Clue有:

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;
    }
}