C# 克隆列表<T>
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/519461/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cloning List<T>
提问by Alex Baranosky
I thought that to clone a List you would just call:
我认为要克隆一个 List 你只需调用:
List<int> cloneList = new List<int>(originalList);
But I tried that in my code and I seem to be getting effects that imply the above is simply doing:
但是我在我的代码中尝试过,我似乎得到了暗示上述内容只是在做的效果:
cloneList = originalList... because changes to cloneList seem to be affecting originalList.
cloneList = originalList... 因为对 cloneList 的更改似乎影响了 originalList。
So what is the way to clone a List?
那么克隆一个List的方法是什么呢?
EDIT:
编辑:
I am thinking of doing something like this:
我正在考虑做这样的事情:
public static List<T> Clone<T>(this List<T> originalList) where T : ICloneable
{
return originalList.ConvertAll(x => (T) x.Clone());
}
EDIT2:
编辑2:
I took the deep copy code suggested by Binoj Antony and created this extension method:
我采用了 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);
}
}
EDIT3:
编辑3:
Now, say the items in the List are structs. What then would result if I called?:
现在,假设 List 中的项目是结构。如果我打电话会导致什么结果?:
List<StructType> cloneList = new List<StructType>(originalList);
I am pretty sure than I would get a List filled with new unique items, correct?
我很确定我会得到一个装满新独特物品的列表,对吗?
采纳答案by Binoj Antony
You can use the below code to make a deep copy of the list or any other object supporting serialization:
您可以使用以下代码制作列表或任何其他支持序列化的对象的深层副本:
Also you can use this for any version of .NET framework from v 2.0 and above, and the similar technique can be applied (removing the usage of generics) and used in 1.1 as well
您也可以将其用于 v 2.0 及更高版本的任何版本的 .NET 框架,并且可以应用类似的技术(删除泛型的使用)并在 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);
}
}
}
You can call it by using
您可以通过使用调用它
List<int> deepCopiedList = GenericCopier<List<int>>.DeepCopy(originalList);
Full code to test if this works:
测试这是否有效的完整代码:
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]);
}
回答by Marc Gravell
This would work...
这将工作...
List<Foo> cloneList = new List<Foo>(originalList);
When you say "because changes to cloneList seem to be affecting originalList." - do you mean changes to the list, or changes to the items...
当您说“因为对 cloneList 的更改似乎影响了 originalList”时。- 你是说清单的变化,还是项目的变化......
Adding / removing / swapping items is changing the list- so if we do:
添加/删除/交换项目正在改变列表- 所以如果我们这样做:
cloneList.Add(anotherItem);
you should find that cloneList
is longer than originalList
. However, if the contents are reference-types (classes), then both lists are still pointing at the same underlying objects - so if we do:
你应该发现它cloneList
比originalList
. 然而,如果内容是引用类型(类),那么两个列表仍然指向相同的底层对象——所以如果我们这样做:
cloneList[0].SomeObjectProperty = 12345;
then this will also show against originalList[0].SomeObjectProperty
- there is only a single object (shared between both lists).
那么这也将显示反对originalList[0].SomeObjectProperty
- 只有一个对象(在两个列表之间共享)。
If this is the problem, you will have to clone the objectsin the list - and then you get into the whole deep vs shallow issue... is this the problem?
如果这是问题所在,您将不得不克隆列表中的对象- 然后您进入整个深与浅的问题......这是问题吗?
For a shallow copy, you might be able to use something very much like the answer here- simply with TTo = TFrom
(perhaps simplify to a single T
).
对于浅拷贝,您可能可以使用与这里的答案非常相似的东西- 只需使用TTo = TFrom
(可能简化为单个T
)。
回答by colithium
It specifically says herethat items are copied over to your new list. So yes, that should work. With value types you'll get complete independence. But remember, with reference types, the lists will be independent but they'll be pointing to the same objects. You'll need to deep copy the list.
它在此处特别说明项目已复制到您的新列表中。所以是的,这应该有效。使用值类型,您将获得完全的独立性。但请记住,对于引用类型,列表将是独立的,但它们将指向相同的对象。您需要深度复制列表。
回答by mafu
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);
This code is perfectly working as intended for me. Are you maybe changing the objects IN the list? The list items won'tget cloned by new List(oldList)
.
这段代码完全符合我的预期。您可能会更改列表中的对象吗?列表项不会被new List(oldList)
.
回答by CMS
Using the List constructor with the original list as parameter will work if the underlying type of the list is a value type. For reference type List elements, I think you want to deep copythem.
如果列表的基础类型是值类型,则使用带有原始列表作为参数的 List 构造函数将起作用。对于引用类型的 List 元素,我认为您想对它们进行深度复制。
You could do something like this:
你可以这样做:
(Assuming that the underlying type implements ICloneable)
(假设底层类型实现了ICloneable)
originalList.ForEach((item) =>
{
cloneList.Add((ICloneable)item.Clone());
}
);
Or using some LINQ:
或者使用一些LINQ:
var cloneList = originalList.Select(item => (ICloneable)item.Clone()).ToList();
回答by Jon Skeet
I doubt that your actualexample would have problems, because int
is a value type. For instance:
我怀疑您的实际示例会出现问题,因为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
}
}
However, as Marc says, if your list contains mutable reference types, cloning the list will only take a shallowcopy - if you mutate the objects that the lists refer to, those changes will be visible via both lists. Replacing elements in one list won't change the equivalent element in the other list though:
但是,正如 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<Dummy> originalList = new List<Dummy>
{
new Dummy(5),
new Dummy(6),
new Dummy(7)
};
List<Dummy> cloneList = new List<Dummy>(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
}
}
To take a "deep clone" of a list where the element type implements ICloneable
, use:
要对元素类型实现的列表进行“深度克隆” ICloneable
,请使用:
List<Foo> cloneList = originalList.ConvertAll(x => (Foo) x.Clone());
However, the real depth of this clone will depend on the implementation of ICloneable
in the element type - ICloneable
is generally regarded as a Bad Thing because its contract is so vague.
然而,这个克隆的真正深度将取决于ICloneable
元素类型中的实现——ICloneable
通常被认为是一件坏事,因为它的契约是如此模糊。
回答by John Leidegren
I vote to not rely on object serialization. It's costly and bad practice.
我投票不依赖对象序列化。这是昂贵的和不好的做法。
public static TObj CloneObject<TObj>(this TObj obj)
where TObj : ICloneable
{
return (TObj)obj.Clone();
}
The above method is a lot more elegant, and you should really care to implement a clonable interface if you need one. You could also make it generic.
上面的方法要优雅得多,如果需要,你应该真正关心实现一个可克隆的接口。你也可以让它通用。
public interface ICloneable<T> : IClonable
{
T CloneObject();
}
Optionally, you could refrain from using the IClonableinterface as a base type as it's poorly maintained. The method name has to change to because you can't do overloads on return types.
或者,您可以避免使用IClonable接口作为基本类型,因为它维护不善。方法名称必须更改为 ,因为您不能对返回类型进行重载。
public static List<T> CloneList(this List<T> source)
where TObj : ICloneable
{
return source.Select(x=>x.CloneObject()).ToList();
}
It's as simple as that.
就这么简单。
Maybe your problem can be solved though using value types instead. They are always pass-by-copy. So you never have to clone anything as long as your data structure is by value.
也许您的问题可以通过使用值类型来解决。它们总是通过复制。所以只要你的数据结构是按值的,你就不必克隆任何东西。
回答by Chris Marisic
I have to add: If you're going to use serialization to facilitate deep copying, why would you clone each individual item? Just clone the entire original list to start with.
我必须补充:如果您要使用序列化来促进深度复制,为什么要克隆每个单独的项目?只需克隆整个原始列表即可开始。
Unless you have logic in place that you only clone nodes that meet certain criteria then do it node by node.
除非你有逻辑,你只克隆满足某些条件的节点,然后逐个节点地进行。