0

我有这个自定义类对象列表:

List<URL> URLs = new List<URL>();

我正在尝试将副本推送到堆栈:

Stack<List<URL>> undo = new Stack<List<URL>>();

List<URL> temp = new List<URL>();
temp.AddRange(new List<URL>(URLs));
undo.Push(temp);

现在,每当我从原始(URL)列表中删除一个对象时,堆栈上的那个(临时)一切都很好。但是,当我从原始(URL)对象内的列表中删除列表元素时,相同的元素会在堆栈上的该对象列表的副本中消失。

我从 URL 中删除对象的方式与删除该对象内的列表元素相同。有谁知道为什么会这样?

4

5 回答 5

1

那是因为 List 基本上是一个数组,即一个引用类型。他们只会互相参考。

使用扩展方法进行深度复制

public static class ExtensionMethod
{  
    public static T DeepClone<T>(this T element)
    { 
        MemoryStream m = new MemoryStream();
        BinaryFormatter b = new BinaryFormatter();
        b.Serialize(m, element);
        m.Position = 0;
        return (T)b.Deserialize(m);
    }
}

并确保你像这样声明你的 URL 类

[Serializable]
public class URL
{
   //..... Your Class
}

并称它为

temp.AddRange(URLs.DeepClone().ToList());
于 2012-04-28T06:57:37.387 回答
0

您需要创建克隆

static class Extensions
{
        public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
        {
                return listToClone.Select(item => (T)item.Clone()).ToList();
        }
}
于 2012-04-28T07:01:56.800 回答
0

列表或堆栈仅保存对其包含的对象的引用。您的两个列表都包含对相同对象的引用。因此,如果您更改从一个列表到达的对象,则该对象与从另一个列表到达的对象相同。

正如@simply denis 建议的那样,您可以在创建第二个列表时克隆对象,以便每个列表都有自己的对象副本。

另一种解决方案是使用不可变对象。例如string,.NET 中的类是不可变的。字符串一旦创建就无法更改。所有字符串操作例程都返回一个新字符串。不可变类型有效地防止了此类问题,因为任何操作都会自动创建一个新实例。

于 2012-04-28T07:02:31.577 回答
0

那是因为您正在制作列表的浅表副本。您会得到两个引用相同URL对象的列表。

(请注意,您实际上是在制作两个浅拷贝,其中new List<URL>(URLs)制作了一个中间拷贝,您只能从中读取然后丢弃。)

如果您想要一个深层副本,您必须URL为该副本创建新实例。我不知道你在URL课堂上实现了什么,但基本上:

List<URL> temp = new List<URL>(URLs.Select(u => u.Clone()));
于 2012-04-28T07:04:42.773 回答
0

这是因为undo中的 URL 对象引用的对象与URLs中的那些 URL 对象相同。因此,修改一个会影响另一个。您需要做的是制作 URL 对象的深层副本。如何进行深拷贝实际上取决于您的 URL 类的实现。这是一种通用方法:如何在 .NET(特别是 C#)中对对象进行深层复制?

但请注意,您可能有更好/更有效的方法来克隆您的URL对象。您需要先向我们展示该类的实现。

于 2012-04-28T07:07:02.100 回答