How do I clone a generic list in C#?

C#GenericsListClone

C# Problem Overview


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?

C# Solutions


Solution 1 - C#

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 2 - C#

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 3 - C#

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][1]

[1]: https://web.archive.org/web/20121230023705/http://en.csharp-online.net/CSharp_Generics_Recipes%E2%80%94Replacing_the_ArrayList_with_Its_Generic_Counterpart "C# Generics Recipes"

Solution 4 - C#

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 - C#

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

Solution 6 - C#

After a slight modification you can also clone:

public static T DeepClone<T>(T obj)
{
    T objResult;
    using (MemoryStream ms = new MemoryStream())
    {
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(ms, obj);
        ms.Position = 0;
        objResult = (T)bf.Deserialize(ms);
    }
    return objResult;
}

Solution 7 - C#

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.

List<T> myList = ...;
List<T> cloneOfMyList = new List<T>(myList);

Changes to myList such as insert or remove will not affect cloneOfMyList and vice versa.

The actual objects the two Lists contain are still the same however.

Solution 8 - C#

If you only care about value types...

And you know the type:

List<int> newList = new List<int>(oldList);

If you don't know the type before, you'll need a helper function:

List<T> Clone<T>(IEnumerable<T> oldList)
{
    return newList = new List<T>(oldList);
}

The just:

List<string> myNewList = Clone(myOldList);

Solution 9 - C#

Use AutoMapper (or whatever mapping lib you prefer) to clone is simple and a lot maintainable.

Define your mapping:

Mapper.CreateMap<YourType, YourType>();

Do the magic:

YourTypeList.ConvertAll(Mapper.Map<YourType, YourType>);

Solution 10 - C#

If you have already referenced Newtonsoft.Json in your project and your objects are serializeable you could always use:

List<T> newList = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(listToCopy))

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.

Solution 11 - C#

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.

public class Student
{
  public Student(Student student)
  {
    FirstName = student.FirstName;
    LastName = student.LastName;
  }

  public string FirstName { get; set; }
  public string LastName { get; set; }
}

// wherever you have the list
List<Student> students;

// and then where you want to make a copy
List<Student> copy = students.Select(s => new Student(s)).ToList();

you'll need the following library where you make the copy

using System.Linq

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.

Solution 12 - C#

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:

public static T DeepCopy<T>(this T value)
{
    JavaScriptSerializer js = new JavaScriptSerializer();

    string json = js.Serialize(value);

    return js.Deserialize<T>(json);
}

Faster option using Newtonsoft JSON:

public static T DeepCopy<T>(this T value)
{
    string json = JsonConvert.SerializeObject(value);

    return JsonConvert.DeserializeObject<T>(json);
}

Solution 13 - C#

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:

public interface IMyCloneable<T>
{
    T Clone();
}

Then I specified the extension:

public static List<T> Clone<T>(this List<T> listToClone) where T : IMyCloneable<T>
{
    return listToClone.Select(item => (T)item.Clone()).ToList();
}

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):

public class VidMark : IMyCloneable<VidMark>
{
    public long Beg { get; set; }
    public long End { get; set; }
    public string Desc { get; set; }
    public int Rank { get; set; } = 0;

    public VidMark Clone()
    {
        return (VidMark)this.MemberwiseClone();
    }
}

And finally, the usage of the extension inside a class:

private List<VidMark> _VidMarks;
private List<VidMark> _UndoVidMarks;

//Other methods instantiate and fill the lists

private void SetUndoVidMarks()
{
    _UndoVidMarks = _VidMarks.Clone();
}

Anybody like it? Any improvements?

Solution 14 - C#

public static Object CloneType(Object objtype)
{
    Object lstfinal = new Object();

    using (MemoryStream memStream = new MemoryStream())
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
        binaryFormatter.Serialize(memStream, objtype); memStream.Seek(0, SeekOrigin.Begin);
        lstfinal = binaryFormatter.Deserialize(memStream);
    }

    return lstfinal;
}

Solution 15 - C#

public class CloneableList<T> : List<T>, ICloneable where T : ICloneable
{
  public object Clone()
  {
    var clone = new List<T>();
    ForEach(item => clone.Add((T)item.Clone()));
    return clone;
  }
}

Solution 16 - C#

    public List<TEntity> Clone<TEntity>(List<TEntity> o1List) where TEntity : class , new()
    {
        List<TEntity> retList = new List<TEntity>();
        try
        {
            Type sourceType = typeof(TEntity);
            foreach(var o1 in o1List)
            {
                TEntity o2 = new TEntity();
                foreach (PropertyInfo propInfo in (sourceType.GetProperties()))
                {
                    var val = propInfo.GetValue(o1, null);
                    propInfo.SetValue(o2, val);
                }
                retList.Add(o2);
            }
            return retList;
        }
        catch
        {
            return retList;
        }
    }

Solution 17 - C#

 //try this
 List<string> ListCopy= new List<string>(OldList);
 //or try
 List<T> ListCopy=OldList.ToList();

Solution 18 - C#

If I need deep copy of collection, I have favorite approach like this:

public static IEnumerable<T> DeepCopy<T>(this IEnumerable<T> collectionToDeepCopy)
{
    var serializedCollection = JsonConvert.SerializeObject(collectionToDeepCopy);
    return JsonConvert.DeserializeObject<IEnumerable<T>>(serializedCollection);
}

Solution 19 - C#

You can use extension method:

namespace extension
{
    public class ext
    {
        public static List<double> clone(this List<double> t)
        {
            List<double> kop = new List<double>();
            int x;
            for (x = 0; x < t.Count; x++)
            {
                kop.Add(t[x]);
            }
            return kop;
        }
   };

}

You can clone all objects by using their value type members for example, consider this class:

public class matrix
{
    public List<List<double>> mat;
    public int rows,cols;
    public matrix clone()
    { 
        // create new object
        matrix copy = new matrix();
        // firstly I can directly copy rows and cols because they are value types
        copy.rows = this.rows;  
        copy.cols = this.cols;
        // but now I can no t directly copy mat because it is not value type so
        int x;
        // I assume I have clone method for List<double>
        for(x=0;x<this.mat.count;x++)
        {
            copy.mat.Add(this.mat[x].clone());
        }
        // then mat is cloned
        return copy; // and copy of original is returned 
    }
};

Note: if you do any change on copy (or clone) it will not affect the original object.

Solution 20 - C#

If you need a cloned list with the same capacity, you can try this:

public static List<T> Clone<T>(this List<T> oldList)
{
    var newList = new List<T>(oldList.Capacity);
    newList.AddRange(oldList);
    return newList;
}

Solution 21 - C#

Using a cast may be helpful, in this case, for a shallow copy:

IList CloneList(IList list)
{
    IList result;
    result = (IList)Activator.CreateInstance(list.GetType());
    foreach (object item in list) result.Add(item);
    return result;
}

applied to generic list:

List<T> Clone<T>(List<T> argument) => (List<T>)CloneList(argument);

Solution 22 - C#

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/

Solution 23 - C#

You could also simply convert the list to an array using ToArray, and then clone the array using Array.Clone(...). Depending on your needs, the methods included in the Array class could meet your needs.

Solution 24 - C#

I've made for my own some extension which converts ICollection of items that not implement IClonable

static class CollectionExtensions
{
    public static ICollection<T> Clone<T>(this ICollection<T> listToClone)
    {
        var array = new T[listToClone.Count];
        listToClone.CopyTo(array,0);
        return array.ToList();
    }
}

Solution 25 - C#

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.

// Example Usage
int[] indexes = getRandomUniqueIndexArray(selectFrom.Length, toSet.Length);

for(int i = 0; i < toSet.Length; i++)
    toSet[i] = selectFrom[indexes[i]];


private int[] getRandomUniqueIndexArray(int length, int count)
{
    if(count > length || count < 1 || length < 1)
        return new int[0];

    int[] toReturn = new int[count];
    if(count == length)
    {
        for(int i = 0; i < toReturn.Length; i++) toReturn[i] = i;
        return toReturn;
    }

    Random r = new Random();
    int startPos = count - 1;
    for(int i = startPos; i >= 0; i--)
    {
        int index = r.Next(length - i);
        for(int j = startPos; j > i; j--)
            if(toReturn[j] >= index)
                toReturn[j]++;
        toReturn[i] = index;
    }

    return toReturn;
}

Solution 26 - C#

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

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Person
{
       ...
      Job JobDescription
       ...
}

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Job
{...
}

private static readonly Type stringType = typeof (string);

public static class CopyFactory
{
    static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();

    private static readonly MethodInfo CreateCopyReflectionMethod;

    static CopyFactory()
    {
        CreateCopyReflectionMethod = typeof(CopyFactory).GetMethod("CreateCopyReflection", BindingFlags.Static | BindingFlags.Public);
    }

    public static T CreateCopyReflection<T>(T source) where T : new()
    {
        var copyInstance = new T();
        var sourceType = typeof(T);

        PropertyInfo[] propList;
        if (ProperyList.ContainsKey(sourceType))
            propList = ProperyList[sourceType];
        else
        {
            propList = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            ProperyList.Add(sourceType, propList);
        }

        foreach (var prop in propList)
        {
            var value = prop.GetValue(source, null);
            prop.SetValue(copyInstance,
                value != null && prop.PropertyType.IsClass && prop.PropertyType != stringType ? CreateCopyReflectionMethod.MakeGenericMethod(prop.PropertyType).Invoke(null, new object[] { value }) : value, null);
        }

        return copyInstance;
    }

I measured it in a simple way, by using the Watcher class.

 var person = new Person
 {
     ...
 };

 for (var i = 0; i < 1000000; i++)
 {
    personList.Add(person);
 }
 var watcher = new Stopwatch();
 watcher.Start();
 var copylist = personList.Select(CopyFactory.CreateCopyReflection).ToList();
 watcher.Stop();
 var elapsed = watcher.Elapsed;

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.

Serializer.DeepClone(personList);

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.

Solution 27 - C#

There is a simple way to clone objects in C# using a JSON serializer and deserializer.

You can create an extension class:

using Newtonsoft.Json;

static class typeExtensions
{
    [Extension()]
    public static T jsonCloneObject<T>(T source)
    {
    string json = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(json);
    }
}

To clone and object:

obj clonedObj = originalObj.jsonCloneObject;

Solution 28 - C#

For a deep clone I use reflection as follows:

public List<T> CloneList<T>(IEnumerable<T> listToClone) {
    Type listType = listToClone.GetType();
    Type elementType = listType.GetGenericArguments()[0];
    List<T> listCopy = new List<T>();
    foreach (T item in listToClone) {
        object itemCopy = Activator.CreateInstance(elementType);
        foreach (PropertyInfo property in elementType.GetProperties()) {
            elementType.GetProperty(property.Name).SetValue(itemCopy, property.GetValue(item));
        }
        listCopy.Add((T)itemCopy);
    }
    return listCopy;
}

You can use List or IEnumerable interchangeably.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFionaView Question on Stackoverflow
Solution 1 - C#Jeff YatesView Answer on Stackoverflow
Solution 2 - C#ajmView Answer on Stackoverflow
Solution 3 - C#Anthony PottsView Answer on Stackoverflow
Solution 4 - C#Patrick DesjardinsView Answer on Stackoverflow
Solution 5 - C#Xavier JohnView Answer on Stackoverflow
Solution 6 - C#AjithView Answer on Stackoverflow
Solution 7 - C#Jader FeijoView Answer on Stackoverflow
Solution 8 - C#James CurranView Answer on Stackoverflow
Solution 9 - C#Derek LiangView Answer on Stackoverflow
Solution 10 - C#ProfNimrodView Answer on Stackoverflow
Solution 11 - C#ztorstriView Answer on Stackoverflow
Solution 12 - C#F.H.View Answer on Stackoverflow
Solution 13 - C#John KurtzView Answer on Stackoverflow
Solution 14 - C#pratikView Answer on Stackoverflow
Solution 15 - C#PeterView Answer on Stackoverflow
Solution 16 - C#shahrooz.bazrafshanView Answer on Stackoverflow
Solution 17 - C#SteveView Answer on Stackoverflow
Solution 18 - C#Martin ZalogaView Answer on Stackoverflow
Solution 19 - C#Furkan KatıView Answer on Stackoverflow
Solution 20 - C#user3245269View Answer on Stackoverflow
Solution 21 - C#Thomas CernyView Answer on Stackoverflow
Solution 22 - C#Dan HView Answer on Stackoverflow
Solution 23 - C#JHapsView Answer on Stackoverflow
Solution 24 - C#Kamil BudziewskiView Answer on Stackoverflow
Solution 25 - C#Adam LewisView Answer on Stackoverflow
Solution 26 - C#Roma BorodovView Answer on Stackoverflow
Solution 27 - C#Albert arnauView Answer on Stackoverflow
Solution 28 - C#ZeyadView Answer on Stackoverflow