如何在 C# 中克隆通用列表?
我有C#中的对象的通用列表,并希望克隆列表。列表中的项目是可包裹的,但是似乎没有一个选择list.clone()
。
有一个简单的方法吗?
I have a generic list of objects in C#, and wish to clone the list. The items within the list are cloneable, but there doesn't seem to be an option to do list.Clone()
.
Is there an easy way around this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
无需将类作为可序列化的标记,在我们的测试中,使用newtonsoft jsonserialializer甚至比使用二进制构造者更快。使用每个对象上可用的扩展方法。
注意:私人成员不是克隆的
标准.NET JavaScriptSerializer选项:
使用 newtonsoft json :
There is no need to flag classes as Serializable and in our tests using the Newtonsoft JsonSerializer even faster than using BinaryFormatter. With extension methods usable on every object.
attention: private members are not cloned
Standard .NET JavascriptSerializer option:
Faster option using Newtonsoft JSON:
如果您需要具有相同容量的克隆列表,则可以尝试以下操作:
If you need a cloned list with the same capacity, you can try this:
您可以使用扩展方法:
您可以通过使用其值类型成员来克隆所有对象,例如,考虑此类:
注意:如果您对复制(或克隆)进行任何更改,它将不会影响原始对象。
You can use extension method:
You can clone all objects by using their value type members for example, consider this class:
Note: if you do any change on copy (or clone) it will not affect the original object.
在这种情况下,使用铸件可能会有所帮助,以备浅副本:
应用于通用列表:
Using a cast may be helpful, in this case, for a shallow copy:
applied to generic list:
如果我需要集合的深层复制,我有最喜欢的方法,如下所示:
If I need deep copy of collection, I have favorite approach like this:
我使用自动应用程序复制对象。我只是设置了将一个对象映射到自身的映射。您可以以任何方式包装此操作。
http://automapper.codeplex.com/
I use automapper to copy an object. I just setup a mapping that maps one object to itself. You can wrap this operation any way you like.
http://automapper.codeplex.com/
您可以使用
List.ConvertAll(Converter)
方法创建一个包含原始列表所有元素的新列表,并使用返回输入值的转换函数。You can use the
List<T>.ConvertAll(Converter<T, T>)
method to create a new list containing all the elements of the original list, and use a conversion function that returns the input value.我已经为自己的一些扩展而制作了,可以转换不实现iClonable的项目的偶像
I've made for my own some extension which converts ICollection of items that not implement IClonable
您也可以简单地使用
toarray
将列表转换为数组,然后使用array.clone.clone(...)
克隆数组。根据您的需求,阵列类中包含的方法可以满足您的需求。
You could also simply convert the list to an array using
ToArray
, and then clone the array usingArray.Clone(...)
.Depending on your needs, the methods included in the Array class could meet your needs.
以下代码应以最小的更改转移到列表中。
基本上,它的工作原理是在每个连续循环中插入更大范围的新随机数。如果已经存在与它相同或更高的数字,请将这些随机数上移一位,以便它们转移到新的更大范围的随机索引中。
The following code should transfer onto a list with minimal changes.
Basically it works by inserting a new random number from a greater range with each successive loop. If there exist numbers already that are the same or higher than it, shift those random numbers up one so they transfer into the new larger range of random indexes.
另一件事:您可以使用反射。如果您正确地缓存,则它将在5.6秒内克隆1,000,000个对象(可悲的是,内在对象为16.4秒)。
我通过使用观察者类以简单的方式测量它。
结果:带有内在对象PersonInstance -16.4,PersonInstance = Null -5.6
CopyFactory只是我的测试类,其中我进行了多次测试,包括表达使用。您可以以扩展名或其他方式以另一种形式实施。不要忘记缓存。
我还没有测试序列化,但是我怀疑一百万个课程的改进。我将尝试一些快速的Protobuf/Newton。
PS:为了阅读简单性,我在这里只使用了自动Property。我可以使用fieldInfo进行更新,或者您应该自行轻松实现。
我最近测试了“ nofollow noreferrer”>“协议缓冲器”> serialializer serializer in the Box中的DeepClone函数。它以100万个简单对象的4.2秒获胜,但是当涉及内部对象时,结果赢得了7.4秒。
摘要:如果您无法访问这些课程,那么这将有所帮助。否则,这取决于对象的计数。我认为您可以使用最多10,000个对象(也许少一点)的反射,但是对于此而言,协议缓冲序列化器的性能还会更好。
Another thing: you could use reflection. If you'll cache this properly, then it'll clone 1,000,000 objects in 5.6 seconds (sadly, 16.4 seconds with inner objects).
I measured it in a simple way, by using the Watcher class.
RESULT: With inner object PersonInstance - 16.4, PersonInstance = null - 5.6
CopyFactory is just my test class where I have dozen of tests including usage of expression. You could implement this in another form in an extension or whatever. Don't forget about caching.
I didn't test serializing yet, but I doubt in an improvement with a million classes. I'll try something fast protobuf/newton.
P.S.: for the sake of reading simplicity, I only used auto-property here. I could update with FieldInfo, or you should easily implement this by your own.
I recently tested the Protocol Buffers serializer with the DeepClone function out of the box. It wins with 4.2 seconds on a million simple objects, but when it comes to inner objects, it wins with the result 7.4 seconds.
SUMMARY: If you don't have access to the classes, then this will help. Otherwise it depends on the count of the objects. I think you could use reflection up to 10,000 objects (maybe a bit less), but for more than this the Protocol Buffers serializer will perform better.
有一种简单的方法可以使用 JSON 序列化器和反序列化器来克隆 C# 中的对象。
您可以创建一个扩展类:
克隆和对象:
There is a simple way to clone objects in C# using a JSON serializer and deserializer.
You can create an extension class:
To clone and object:
对于深度克隆,我使用反射,如下所示:
您可以互换使用 List 或 IEnumerable。
For a deep clone I use reflection as follows:
You can use List or IEnumerable interchangeably.
它可以使用不同的参考来复制现有列表。在C#中执行此操作的最简单方法是
DeepClone
选项。It may work to copy the existing list with a different reference. The simplest way to do this in C# is the
DeepClone
option.如果您的元素是值类型,那么您可以这样做:
但是,如果它们是引用类型并且您想要深层复制(假设您的元素正确实现了ICloneable),您可以这样做:
显然,替换上述泛型中的
ICloneable
并使用实现ICloneable
的任何元素类型进行转换。如果您的元素类型不支持
ICloneable
但有复制构造函数,您可以这样做:就个人而言,我会避免使用
ICloneable
因为需要保证所有成员的深拷贝。相反,我建议使用复制构造函数或像YourType.CopyFrom(YourType itemToCopy)
这样的工厂方法,它返回YourType
的新实例。这些选项中的任何一个都可以通过方法(扩展或其他方式)包装。
If your elements are value types, then you can just do:
However, if they are reference types and you want a deep copy (assuming your elements properly implement
ICloneable
), you could do something like this:Obviously, replace
ICloneable
in the above generics and cast with whatever your element type is that implementsICloneable
.If your element type doesn't support
ICloneable
but does have a copy-constructor, you could do this instead:Personally, I would avoid
ICloneable
because of the need to guarantee a deep copy of all members. Instead, I'd suggest the copy-constructor or a factory method likeYourType.CopyFrom(YourType itemToCopy)
that returns a new instance ofYourType
.Any of these options could be wrapped by a method (extension or otherwise).
您可以使用扩展方法。
You can use an extension method.
对于浅拷贝,您可以使用通用 List 类的 GetRange 方法。
引用自: 泛型食谱
For a shallow copy, you can instead use the GetRange method of the generic List class.
Quoted from: Generics Recipes
这是使用C#和.NET 2.0进行操作的一种方法。您的对象需要为
[serializable()]
。目标是失去所有参考资料并建立新的参考。This is one way to do it with C# and .NET 2.0. Your object requires to be
[Serializable()]
. The goal is to lose all references and build new ones.要克隆列表,只需调用
.tolist()
。这创建了浅副本。To clone a list just call
.ToList()
. This creates a shallow copy.稍作修改后,您还可以克隆:
After a slight modification you can also clone:
除非您需要
list&lt; t&gt;
中每个对象的实际克隆,否则克隆列表的最佳方法是创建一个新列表,其中旧列表作为集合参数。更改
myList
(例如插入或删除)不会影响cloneofmylist
,反之亦然。但是,两个列表包含的实际对象仍然相同。
Unless you need an actual clone of every single object inside your
List<T>
, the best way to clone a list is to create a new list with the old list as the collection parameter.Changes to
myList
such as insert or remove will not affectcloneOfMyList
and vice versa.The actual objects the two Lists contain are still the same however.
使用 AutoMapper(或任何您喜欢的映射库)进行克隆很简单并且易于维护。
定义您的映射:
发挥魔法:
Use AutoMapper (or whatever mapping lib you prefer) to clone is simple and a lot maintainable.
Define your mapping:
Do the magic:
如果您只关心值类型...
并且您知道类型:
如果您之前不知道类型,则需要一个辅助函数:
只是:
If you only care about value types...
And you know the type:
If you don't know the type before, you'll need a helper function:
The just:
如果您已经在项目中引用了newtonsoft.json,并且您的对象是可序列化的,则可以始终使用:
可能不是最有效的方法,但是除非您这样做1000次1000次,否则您甚至可能不会注意到速度不同之处。
If you have already referenced Newtonsoft.Json in your project and your objects are serializeable you could always use:
Possibly not the most efficient way to do it, but unless you're doing it 100s of 1000s of times you may not even notice the speed difference.
对于深层副本,可观的是正确的解决方案,但这是使用构造函数而不是可lon式接口的类似方法。
您将需要以下库进行副本,
也可以使用循环而不是System.linq,但是Linq使其简洁明了。同样,您可以像其他答案所建议的那样做并制定扩展方法等,但是这些都不是必需的。
For a deep copy, ICloneable is the correct solution, but here's a similar approach to ICloneable using the constructor instead of the ICloneable interface.
you'll need the following library where you make the copy
you could also use a for loop instead of System.Linq, but Linq makes it concise and clean. Likewise you could do as other answers have suggested and make extension methods, etc., but none of that is necessary.
如果有人读过这个,我会很幸运...但是为了不在我的克隆方法中返回类型对象列表,我创建了一个接口:
然后我指定了扩展名:
这是我的接口中的接口的实现音视频标记软件。我想让我的 Clone() 方法返回 VidMark 列表(而 ICloneable 接口希望我的方法返回对象列表):
最后,在类中使用扩展:
有人喜欢吗?有什么改进吗?
I'll be lucky if anybody ever reads this... but in order to not return a list of type object in my Clone methods, I created an interface:
Then I specified the extension:
And here is an implementation of the interface in my A/V marking software. I wanted to have my Clone() method return a list of VidMark (while the ICloneable interface wanted my method to return a list of object):
And finally, the usage of the extension inside a class:
Anybody like it? Any improvements?