How do I clone a generic list in C#?
Solution 1
You can use an extension method.
static class Extensions
{
public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
{
return listToClone.Select(item => (T)item.Clone()).ToList();
}
}
Solution 2
If your elements are value types, then you can just do:
List<YourType> newList = new List<YourType>(oldList);
However, if they are reference types and you want a deep copy (assuming your elements properly implement ICloneable
), you could do something like this:
List<ICloneable> oldList = new List<ICloneable>();
List<ICloneable> newList = new List<ICloneable>(oldList.Count);
oldList.ForEach((item) =>
{
newList.Add((ICloneable)item.Clone());
});
Obviously, replace ICloneable
in the above generics and cast with whatever your element type is that implements ICloneable
.
If your element type doesn't support ICloneable
but does have a copy-constructor, you could do this instead:
List<YourType> oldList = new List<YourType>();
List<YourType> newList = new List<YourType>(oldList.Count);
oldList.ForEach((item)=>
{
newList.Add(new YourType(item));
});
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 like YourType.CopyFrom(YourType itemToCopy)
that returns a new instance of YourType
.
Any of these options could be wrapped by a method (extension or otherwise).
Solution 3
For a shallow copy, you can instead use the GetRange method of the generic List class.
List<int> oldList = new List<int>( );
// Populate oldList...
List<int> newList = oldList.GetRange(0, oldList.Count);
Quoted from: Generics Recipes
Solution 4
public static object DeepClone(object obj)
{
object objResult = null;
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
bf.Serialize(ms, obj);
ms.Position = 0;
objResult = bf.Deserialize(ms);
}
return objResult;
}
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.
Solution 5
To clone a list just call .ToList(). This creates a shallow copy.
Microsoft (R) Roslyn C# Compiler version 2.3.2.62116
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> var x = new List<int>() { 3, 4 };
> var y = x.ToList();
> x.Add(5)
> x
List<int>(3) { 3, 4, 5 }
> y
List<int>(2) { 3, 4 }
>
Fiona
Updated on July 20, 2022Comments
-
Fiona almost 2 years
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?
-
orip over 15 yearsYou should say if you're looking for a deep copy or a shallow copy
-
Colonel Panic over 11 yearsWhat are deep and shallow copies?
-
Nathan Koop over 11 years@ColonelPanic en.wikipedia.org/wiki/Object_copy#Shallow_copy
-
Chris over 11 years@orip Isn't
clone()
by definition a deep copy? In C# you can pass pointers around easily with =, I thought. -
orip over 11 years@Chris a shallow copy copies one level deeper than pointer copy. Eg a shallow copy of a list will have the same elements, but will be a different list.
-
Admin over 8 yearsWhere a deep copy will be a new list, with new items, but the contents are the same.
-
Ahmed Sabry over 5 yearsCheck this Answer: stackoverflow.com/a/52097307/4707576 about: Cloning objects without Serialization
-
-
Jeff Yates over 15 yearsThis doesn't clone the elements.
-
MichaelGG over 15 yearsI think List<T>.ConvertAll might look nicer than creating a new list and doing a foreach+add.
-
MichaelGG over 15 yearsI think List.ConvertAll might do this in faster time, since it can pre-allocate the entire array for the list, versus having to resize all the time.
-
Jeff Yates over 15 yearsGood point. I must admit, I'm still coming to grips with all the LINQ calls myself.
-
slugster about 14 years+1 - i like this answer - it is quick, dirty, nasty and very effective. I used in silverlight, and used the DataContractSerializer as the BinarySerializer was not available. Who needs to write pages of object cloning code when you can just do this? :)
-
Popplars over 13 years+1 So in summary, it is impossible to provide a deep clone function for a Generic.List. Is that right?
-
Jeff Yates over 13 years@Dimitri: No, that's not true. The problem is, when
ICloneable
was defined, the definition never stated whether the clone was deep or shallow, so you cannot determine which type of Clone operation will be done when an object implements it. This means that if you want to do a deep clone ofList<T>
, you will have to do it withoutICloneable
to be sure it is a deep copy. -
Odrade over 13 yearsI like this. While it's nice to do things "right", quick and dirty often comes in handy.
-
phoog over 13 yearsWhy not use the AddRange method? (
newList.AddRange(oldList.Select(i => i.Clone())
ornewList.AddRange(oldList.Select(i => new YourType(i)
) -
Jeff Yates over 13 years@phoog: It's another option, sure. It doesn't make much difference.
-
phoog over 13 years@Jeff Yates: It does make a difference if the collection argument to AddRange implements ICollection<T>. In that case, the list uses the collection's count property so it doesn't have to increase its capacity more than once. This (potentially) saves on memory allocations. In most contexts, of course, the savings is negligible, so for the most part, you're right, it doesn't make much difference.
-
Jeff Yates over 13 years@phoog: That's an optimization I'd avoid unless it was clear from profiling that it was needed.
-
phoog over 13 years@Jeff Yates: Fair enough. I've been working with an application that uses huge lists whose arrays are big enough to be in the large object heap, so it's a useful optimization in that case. I'm curious though, why you would avoid it.
-
Jeff Yates over 13 years@phoog: I think that it is a little less readable/understandable when scanning the code, that's all. Readability wins for me.
-
markmnl almost 13 yearswhy not use ToArray() - that does create a deep copy - it uses memmove effectively
-
Jeff Yates almost 13 years@Feanor: That's not exactly true. It copies the values of the immediate elements, but what about child values? How does it know if each reference in my type should be its own unique copy or a shared instance? It doesn't. A deep copy is one that traverses the entire object graph for an instance and makes sure that all things it contains or references are also copies and that their references are copies, etc. etc.
-
markmnl almost 13 yearsyes, of course you are right, sorry, it is very unlikely the class only consists of value types
-
Arkiliknam over 12 yearsYou can also achieve this by using the List<T>'s contructor to specify a List<T> from which to copy from. eg var shallowClonedList = new List<MyObject>(originalList);
-
Dan Bechard over 11 yearsI often use
List<int> newList = oldList.ToList()
. Same effect. However, Arkiliknam's solution is best for readability in my opinion. -
supercat over 10 years@JeffYates: One insufficiently-considered wrinkle is that things generally only need to be copied if there exists some execution path which would mutate them. It's very common to have immutable types hold a reference to an instance of mutable type, but never expose that instance to anything that will mutate it. Needless copying of things that aren't ever going to change can sometimes be a major performance drain, increasing memory usage by orders of magnitude.
-
Jeff Yates over 10 years@supercat: Indeed, it is up to you to determine what needs to be cloned when cloning an object, which is yet another reason why cloning can be so difficult to get right.
-
supercat over 10 years@JeffYates: What's unfortunate about that is that the rules aren't complicated--they just depend upon something the type system doesn't have any standard way of expressing. If the type system could decorate storage location types with a couple flag attributes to indicate whether they encapsulate identity, mutable state, both, or neither, efficient and reliable deep cloning would be easy in 99% of cases, even for objects that are inherently not serializable. Note that those should be traits of storage location types, not heap types, and not fields.
-
supercat over 10 yearsIf an
Identity<T>
was regarded as a reference to aT
used to encapsulate identity only, and aMutableState<T>
used to refer to one that encapsulates mutable state but not identity, a copy of aMutableState<List<Identity<T>>>
should hold a reference to a new list with references to the same objects; a copy of aMutableState<List<MutableState<T>>>
should hold a reference to a a new list with copies of the items therein. -
Jeff Yates over 10 yearsAt first glance, it seems like an overly complex solution to a corner-case issue. Instead, implementing objects to support serialization would ensure that serializing/deserializing objects can be used to clone them and then the designer of each object is in control of what cloning means to them.
-
raiserle over 10 yearsQuick! but: Why dirty?
-
Auguste Van Nieuwenhuyzen about 10 yearsI just needed to be reminded of the first line - so I much prefer this answer, thanks @JeffYates!
-
IbrarMumtaz almost 10 years@MichaelGG, what if you don't want to Convert but just Clone/Duplicate the items in the list? Would this work? || var clonedList = ListOfStrings.ConvertAll(p => p);
-
Brandon Arnold over 9 years@IbrarMumtaz: That is the same as var clonedList = new List<string>(ListOfStrings);
-
Jonathon Cwik over 9 yearsIt's not about the speed difference, it's about the readability. If I came to this line of code I would slap my head and wonder why they introducted a third-party library to serialize and then deserialize an object which I would have no idea why it's happening. Also, this wouldn't work for a model list with objects that have a circular structure.
-
Plutoz about 9 yearsNice solution! By the way I prefer public static List<T> CLone<T>... It is more useful in the cases like this, because no further cast needed: List<MyType> cloned = listToClone.Clone();
-
RandallTo almost 9 yearsThis deep clones and is fast and easy. Carefull on other suggestions on this page. I tried several and they don't deep clone.
-
George Birbilis almost 9 yearsseems some collections (e.g. DataGrid's SelectedItems at Silverlight) skip the implementation of CopyTo which is a problem with this approach
-
Roman almost 9 yearsI like nasty and dirty^^ It's like JSON.parse(JSON.stringify(obj)). Brilliant!
-
Tuukka Haapaniemi over 8 yearsOnly negative aspect, if you can call it that, is that your classes have to be marked Serializable for this to work.
-
juharr over 8 yearsI agree with @phoog, but If you think
AddRange
with Linq is less readable, then why not just useforeach
.ForEach
is harder to understand, harder to debug, and introduces closure semantics -
Developer63 over 8 yearsThis code worked excellently for me for deep cloning. The app is migrating document boilerplate from Dev to QA to Prod. Each object is a packet of several document template objects, and each document in turn is comprised of a list of paragraph objects. This code let me serialize the .NET "source" objects and immediately deserialize them to new "target" objects, which then get saved to a SQL database in a different environment. After tons of research, I found lots of stuff, much of which was too cumbersome, and decided to try this. This short and flexible approach was "just right"!
-
Seidleroni over 8 yearsI agree with user49126, I'm seeing that it is a shallow copy and changes made to one list are reflected in the other list.
-
Wellington Zanelli about 8 years@Seidleroni, you are wrong. The changes made to the list itens are afected on the other list, changes in the list itself are not.
-
Elliot Chen almost 8 yearsThis is shallow copy.
-
Brian Ogden almost 8 years@BrandonArnold you are wrong, what if T is an object, not value type?
-
Brandon Arnold almost 8 years@BrianOgden Isn't the ConvertAll delegate in his example also retaining reference types? The arrow function would need a copy constructor or cloning serializer (e.g. p => new PType(p)).
-
Brian Ogden almost 8 yearsSorry @BrandonArnold you right, I thought your comment was in reference to the answer, you commenting on a comment from IbrarMumtaz, my bad, carry on as you were :)
-
Bernoulli Lizard over 7 yearsThis does not work; changes to the values in the cloned array STILL change the values in the original list.
-
zainul over 7 yearsyou can use var clonedList = ListOfStrings.ConvertAll(p => p); as given by @IbrarMumtaz .... Works effectively... Changes to one list are kept to itself and doesn't to reflect in another
-
himanshupareek66 over 6 yearsPrivate members are not cloned using the JSON method. stackoverflow.com/a/78612/885627
-
Bence Végert over 6 yearsDo not forget the T should be serializable, otherwise you get System.Runtime.Serialization.SerializationException.
-
Mark G over 6 yearsA little warning this is a shallow copy ... This will create two list objects, but the objects inside will be the same. I.e. changing one property will change the same object / property in the original list.
-
Matt about 6 yearsGood answer. One hint: You could add
if (!obj.GetType().IsSerializable) return default(T);
as the first statement which prevents the exception. And if you change it to an extension method, you could even use the Elvis operator likevar b = a?.DeepClone();
(givenvar a = new List<string>() { "a", "b" };
for example). -
ruffin about 6 yearsI think the follow-on to @supercat is that your current taxonomy has a hole. You have value types & reference types you might mutate, but not reference types where shallow copies are appropriate. Perhaps: "If your elements are value types [or are reference types where you're only worried list membership], then you can just do [the shallow clone constructor]". With reference types, you may want to edit the membership of
newList
w/o affecting membership ofoldList
, though you want edits to elements shared. TL;DR: Maybe make shallow vs. deep use cases w/ ref types explicit. -
mko over 5 yearsHow is this a shallow copy?
-
kenno over 4 yearsThat's called a "copy constructor". It's a v error prone approach, whenever you add a new field to Student, you have to remember to add it to the copy constructor. The main idea behind "clone" is to avoid that problem.
-
ztorstri over 4 yearsEven with ICloneable, you have to have a "Clone" method on your class. Unless you use reflection (which you could also use in the above approach), that Clone method is going to look real similar to the copy constructor approach above, and will suffer from the same issue of having to update for new/changed fields. But that's saying "The class has to be updated when fields of the class change". Of course it does ;)
-
Everts over 4 yearsIsn't this just half the answer since it relies on an implementation of ICloneable, which would be the important part of the question?
-
Nick Gallimore over 4 years@WellingtonZanelli Just confirmed that removing an element from myList removes it from cloneOfMyList as well.
-
NetMage over 3 years@DanBechard Years later, but I prefer
ToList
as it avoids all the redundancies - I wonder which is actually more performant... looked it up. Looks listToList
callsnew List<T>
which ultimately will useArray.CopyTo
, so about the same. -
AH. about 3 yearsI agree it is only half the answer as it is missing the IClonable part.
-
ToolmakerSteve almost 3 years@NickGallimore - If true, that would be a surprising bug in List implementation. The definition of a new list is that it contains the same items at the time of creation, but has its own "state". Each item has two references to it, but any operation on the list itself is supposed to be independent.
-
ToolmakerSteve almost 3 yearsThere is a SERIOUS LIMITATION with this approach. Consider
class StudentB : Student
. In a list ofStudents
, some might beStudentB
s.new Student(s)
will do the wrong thing - it will create aStudent
, not aStudentB
.ICloneable
does not have this limitation. (assuming StudentB also implements ICloneable.) -
Alexandru Dicu over 2 yearsThis is a very basic example that has no use in real world programming. You have to clone a list of complex objects with children of lists of other objects and so on.
-
RBZ over 2 yearsI am surprised, no one has mentioned the issue that models must implement ICloneable and IClonable.Clone() returns type object, and so takes a boxing performance hit.
-
Preza8 over 2 yearsSerializing data to text is very resource expensive compared to the actual job that needs to be done. This can be ok if you are not working on production code tho, just a one-time thing.