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

本文关键字:列表 修改 新列表 | 更新日期: 2023-09-27 18:10:42

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

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

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

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

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

您可以序列化和反序列化列表以创建深度副本

当你创建列表的深度拷贝时,你是在创建新的线索对象,而不是像在浅拷贝中那样只是引用它们

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

这是因为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;
    }
}