当前位置:  开发笔记 > 编程语言 > 正文

克隆列表<T>

如何解决《克隆列表<T>》经验,为你挑选了3个好方法。

我想要克隆一个List你只需要调用:

List cloneList = new List(originalList);

但是我在我的代码中尝试了这一点,我似乎得到的效果暗示上面只是在做:

cloneList = originalList ...因为对cloneList的更改似乎正在影响originalList.

那么克隆List的方法是什么?

编辑:

我在考虑做这样的事情:

public static List Clone(this List originalList) where T : ICloneable
{
    return originalList.ConvertAll(x => (T) x.Clone());
}

EDIT2:

我拿了Binoj Antony建议的深拷贝代码并创建了这个扩展方法:

public static T DeepCopy(this T original) where T : class
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();
        binaryFormatter.Serialize(memoryStream, original);
        memoryStream.Seek(0, SeekOrigin.Begin);
        return (T)binaryFormatter.Deserialize(memoryStream);
    }
}

EDIT3:

现在,假设列表中的项目是结构.如果我打电话会怎么样?:

List cloneList = new List(originalList);

我非常肯定,我会得到一个填充了新的独特项目的列表,对吗?



1> Marc Gravell..:

这会工作......

List cloneList = new List(originalList);

当你说"因为对cloneList的更改似乎正在影响originalList".- 您的意思是更改列表,还是更改项目 ......

添加/删除/交换项目正在更改列表 - 因此,如果我们这样做:

cloneList.Add(anotherItem);

你会发现它cloneList比...更长originalList.但是,如果内容是引用类型(类),那么两个列表仍然指向相同的底层对象 - 所以如果我们这样做:

cloneList[0].SomeObjectProperty = 12345;

然后这也将显示originalList[0].SomeObjectProperty- 只有一个对象(两个列表之间共享).

如果这是问题,你将不得不克隆列表中的对象 - 然后你进入整个深层和浅层问题......这是问题吗?

对于浅拷贝,你也许能够使用的东西非常喜欢的答案在这里 -简单地用TTo = TFrom(也许简化为一个单一的T).



2> Binoj Antony..:

您可以使用以下代码制作列表的深层副本或支持序列化的任何其他对象:

此外,您可以将此用于v 2.0及更高版本的任何.NET框架版本,并且可以应用类似技术(删除泛型的使用)并在1.1中使用

public static class GenericCopier
{
    public static T DeepCopy(object objectToCopy)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, objectToCopy);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return (T) binaryFormatter.Deserialize(memoryStream);
        }
    }
}

你可以用它来调用它

List deepCopiedList = GenericCopier>.DeepCopy(originalList);

测试是否有效的完整代码:

static void Main(string[] args)
{
    List originalList = new List(5);
    Random random = new Random();
    for(int i = 0; i < 5; i++)
    {
        originalList.Add(random.Next(1, 100));
        Console.WriteLine("List[{0}] = {1}", i, originalList[i]);
    }
    List deepCopiedList = GenericCopier>.DeepCopy(originalList);
    for (int i = 0; i < 5; i++)
        Console.WriteLine("deepCopiedList[{0}] value is {1}", i, deepCopiedList[i]);
}



3> Jon Skeet..:

我怀疑你的实际例子会有问题,因为它int是一个值类型.例如:

using System;
using System.Collections.Generic;

class Test
{
    static void Main()
    {
        List originalList = new List { 5, 6, 7 };
        List cloneList = new List(originalList);

        cloneList.Add(8);
        cloneList[0] = 2;
        Console.WriteLine(originalList.Count); // Still 3
        Console.WriteLine(originalList[0]); // Still 5
    }
}

但是,正如Marc所说,如果您的列表包含可变引用类型,则克隆列表将只采用浅表副本 - 如果您改变列表引用的对象,则这些更改将通过两个列表可见.替换一个列表中的元素不会更改另一个列表中的等效元素:

using System;
using System.Collections.Generic;

class Dummy
{
    public int Value { get; set; }

    public Dummy (int value)
    {
        this.Value = value;
    }
}

class Test
{
    static void Main()
    {
        List originalList = new List 
        {
            new Dummy(5),
            new Dummy(6),
            new Dummy(7)
        };

        List cloneList = new List(originalList);

        cloneList[0].Value = 1;
        cloneList[1] = new Dummy(2);
        Console.WriteLine(originalList[0].Value); // Changed to 1
        Console.WriteLine(originalList[1].Value); // Still 6
    }
}

要对元素类型实现的列表进行"深度克隆" ICloneable,请使用:

List cloneList = originalList.ConvertAll(x => (Foo) x.Clone());

但是,这个克隆的真正深度将取决于ICloneable元素类型的实现- ICloneable通常被认为是一件坏事,因为它的合同是如此模糊.

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有