C# 克隆列表<;T>;

C# 克隆列表<;T>;,c#,.net,C#,.net,我认为要克隆一个列表,您只需调用: List<int> cloneList = new List<int>(originalList); 列表克隆列表=新列表(原始列表); 但我在我的代码中尝试了这一点,我似乎得到了暗示上述操作的效果: 克隆列表=原始列表。。。因为克隆列表的改变似乎影响了原创者 那么,克隆列表的方法是什么呢 编辑: 我正在考虑这样做: public static List<T> Clone<T>(this List<T&

我认为要克隆一个列表,您只需调用:

List<int> cloneList = new List<int>(originalList);
列表克隆列表=新列表(原始列表);
但我在我的代码中尝试了这一点,我似乎得到了暗示上述操作的效果:

克隆列表=原始列表。。。因为克隆列表的改变似乎影响了原创者

那么,克隆列表的方法是什么呢

编辑:

我正在考虑这样做:

public static List<T> Clone<T>(this List<T> originalList) where T : ICloneable
{
    return originalList.ConvertAll(x => (T) x.Clone());
}
公共静态列表克隆(此列表原始列表),其中T:ICloneable
{
返回originalList.ConvertAll(x=>(T)x.Clone());
}
编辑2:

我采用Binoj Antony建议的深度复制代码,创建了这个扩展方法:

public static T DeepCopy<T>(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);
    }
}
public static T DeepCopy(这是T原件),其中T:class
{
使用(MemoryStream MemoryStream=new MemoryStream())
{
BinaryFormatter BinaryFormatter=新的BinaryFormatter();
序列化(memoryStream,原始);
memoryStream.Seek(0,SeekOrigin.Begin);
返回(T)二进制格式化程序。反序列化(memoryStream);
}
}
编辑3:

现在,假设列表中的项目是结构。如果我打电话会有什么结果

List<StructType> cloneList = new List<StructType>(originalList);
列表克隆列表=新列表(原始列表);
我很确定我会得到一个充满新的独特项目的列表,对吗?

这会有用的

List<Foo> cloneList = new List<Foo>(originalList);
您应该发现
克隆列表
原始列表
长。但是,如果内容是引用类型(类),那么两个列表仍然指向相同的底层对象-如果我们这样做:

cloneList.Add(anotherItem);
cloneList[0].SomeObjectProperty = 12345;
然后,这也将针对原始列表[0]显示。SomeObjectProperty-只有一个对象(在两个列表之间共享)

如果这就是问题所在,您将不得不克隆列表中的对象,然后进入整个深与浅的问题。。。这就是问题所在吗

对于浅表副本,您可能可以使用非常类似于答案的内容—只需使用
TTo=TFrom
(可能简化为单个
T
)。

它明确表示项目将复制到新列表中。所以是的,这应该行得通。使用值类型,您将获得完全的独立性。但是请记住,对于引用类型,列表将是独立的,但它们将指向相同的对象。你需要深度复制列表


            List list = new List ();
            List clone = new List (list);
            list.Add (new int ());
            Debug.Assert (list != clone);
            Debug.Assert (list.Count == 1);
            Debug.Assert (clone.Count == 0);

这段代码完全符合我的预期。您是否正在更改列表中的对象?如果列表的基础类型是值类型,则使用以原始列表为参数的列表构造函数将不会克隆列表项。对于引用类型的列表元素,我认为您需要深度复制它们

你可以这样做:

public static List<T> Clone<T>(this List<T> originalList) where T : ICloneable
{
    return originalList.ConvertAll(x => (T) x.Clone());
}
(假设基础类型实现了ICloneable)

或者使用一些:

我怀疑您的实际示例会有问题,因为
int
是一种值类型。例如:

using System;
using System.Collections.Generic;

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

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

但是,此克隆的实际深度将取决于元素类型中
ICloneable
的实现-
ICloneable
通常被视为一件坏事,因为它的契约非常模糊。

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

您还可以将其用于v2.0及以上版本的任何.NETFramework,类似的技术也可以应用(删除泛型的使用)并在1.1中使用

public static class GenericCopier<T>
{
    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);
        }
    }
}
公共静态类GenericCopier
{
公共静态T DeepCopy(对象对象复制)
{
使用(MemoryStream MemoryStream=new MemoryStream())
{
BinaryFormatter BinaryFormatter=新的BinaryFormatter();
序列化(memoryStream,objectToCopy);
memoryStream.Seek(0,SeekOrigin.Begin);
返回(T)二进制格式化程序。反序列化(memoryStream);
}
}
}
你可以使用

List<int> deepCopiedList = GenericCopier<List<int>>.DeepCopy(originalList);
List deepCopiedList=GenericCopier.DeepCopy(原始列表);
要测试此功能是否有效的完整代码:

static void Main(string[] args)
{
    List<int> originalList = new List<int>(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<int> deepCopiedList = GenericCopier<List<int>>.DeepCopy(originalList);
    for (int i = 0; i < 5; i++)
        Console.WriteLine("deepCopiedList[{0}] value is {1}", i, deepCopiedList[i]);
}
static void Main(字符串[]args)
{
列表原始列表=新列表(5);
随机=新随机();
对于(int i=0;i<5;i++)
{
原始列表.Add(random.Next(1100));
WriteLine(“List[{0}]={1}”,i,originalList[i]);
}
List deepCopiedList=GenericCopier.DeepCopy(原始列表);
对于(int i=0;i<5;i++)
WriteLine(“deepCopiedList[{0}]值为{1}”,i,deepCopiedList[i]);
}

我投票决定不依赖对象序列化。这既昂贵又不好

public static TObj CloneObject<TObj>(this TObj obj)
    where TObj : ICloneable
{
    return (TObj)obj.Clone();
}
公共静态TObj CloneObject(此TObj对象)
托布:我在哪里
{
return(TObj)obj.Clone();
}
上面的方法要优雅得多,如果需要,您应该真正注意实现一个可关闭的接口。你也可以让它通用

public interface ICloneable<T> : IClonable
{
    T CloneObject();
}
公共接口可IClonable:IClonable
{
T CloneObject();
}
或者,您可以避免将接口用作基本类型,因为它的维护很差。方法名称必须更改为,因为无法对返回类型执行重载

public static List<T> CloneList(this List<T> source)
    where TObj : ICloneable
{
    return source.Select(x=>x.CloneObject()).ToList();
}
公共静态列表克隆列表(此列表源)
托布:我在哪里
{
返回source.Select(x=>x.CloneObject()).ToList();
}
就这么简单


也许你的问题可以通过使用值类型来解决。他们总是被抄袭。因此,只要数据结构是按值进行的,就不必克隆任何内容。

我必须补充一点:如果要使用序列化来促进深度复制,为什么要克隆每个单独的项?只需克隆整个原始列表即可开始


除非您有逻辑,只克隆满足特定条件的节点,然后逐个节点进行克隆。

因此,它似乎不起作用,这意味着我做错了什么,因为您提到的方式就是我目前正在做的方式。

public static TObj CloneObject<TObj>(this TObj obj)
    where TObj : ICloneable
{
    return (TObj)obj.Clone();
}
public interface ICloneable<T> : IClonable
{
    T CloneObject();
}
public static List<T> CloneList(this List<T> source)
    where TObj : ICloneable
{
    return source.Select(x=>x.CloneObject()).ToList();
}