Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloning List<T>

Tags:

I thought that to clone a List you would just call:

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.

So what is the way to clone a 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:

I took the deep copy code suggested by Binoj Antony and created this extension method:

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:

Now, say the items in the List are structs. What then would result if I called?:

List<StructType> cloneList = new List<StructType>(originalList); 

I am pretty sure than I would get a List filled with new unique items, correct?

like image 756
Alex Baranosky Avatar asked Feb 06 '09 07:02

Alex Baranosky


People also ask

How do I clone a list?

To clone a list, one can iterate through the original list and use the clone method to copy all the list elements and use the add method to append them to the list. Approach: Create a cloneable class, which has the clone method overridden. Create a list of the class objects from an array using the asList method.

How do I assign a value from one list to another in C#?

To add the contents of one list to another list which already exists, you can use: targetList. AddRange(sourceList); If you're just wanting to create a new copy of the list, see the top answer.


2 Answers

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...

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[0].SomeObjectProperty = 12345; 

then this will also show against originalList[0].SomeObjectProperty - there is only a single object (shared between both lists).

If this is the problem, you will have to clone the objects in 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).

like image 112
Marc Gravell Avatar answered Sep 28 '22 19:09

Marc Gravell


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

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]); } 
like image 31
Binoj Antony Avatar answered Sep 28 '22 19:09

Binoj Antony