How do I clone a generic list in C#?

780,381

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 }
> 
Share:
780,381
Fiona
Author by

Fiona

Updated on July 20, 2022

Comments

  • Fiona
    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
      orip over 15 years
      You should say if you're looking for a deep copy or a shallow copy
    • Colonel Panic
      Colonel Panic over 11 years
      What are deep and shallow copies?
    • Nathan Koop
      Nathan Koop over 11 years
    • Chris
      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
      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
      Admin over 8 years
      Where a deep copy will be a new list, with new items, but the contents are the same.
    • Ahmed Sabry
      Ahmed Sabry over 5 years
      Check this Answer: stackoverflow.com/a/52097307/4707576 about: Cloning objects without Serialization
  • Jeff Yates
    Jeff Yates over 15 years
    This doesn't clone the elements.
  • MichaelGG
    MichaelGG over 15 years
    I think List<T>.ConvertAll might look nicer than creating a new list and doing a foreach+add.
  • MichaelGG
    MichaelGG over 15 years
    I 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
    Jeff Yates over 15 years
    Good point. I must admit, I'm still coming to grips with all the LINQ calls myself.
  • slugster
    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
    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
    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 of List<T>, you will have to do it without ICloneable to be sure it is a deep copy.
  • Odrade
    Odrade over 13 years
    I like this. While it's nice to do things "right", quick and dirty often comes in handy.
  • phoog
    phoog over 13 years
    Why not use the AddRange method? (newList.AddRange(oldList.Select(i => i.Clone()) or newList.AddRange(oldList.Select(i => new YourType(i))
  • Jeff Yates
    Jeff Yates over 13 years
    @phoog: It's another option, sure. It doesn't make much difference.
  • phoog
    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
    Jeff Yates over 13 years
    @phoog: That's an optimization I'd avoid unless it was clear from profiling that it was needed.
  • phoog
    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
    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
    markmnl almost 13 years
    why not use ToArray() - that does create a deep copy - it uses memmove effectively
  • Jeff Yates
    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
    markmnl almost 13 years
    yes, of course you are right, sorry, it is very unlikely the class only consists of value types
  • Arkiliknam
    Arkiliknam over 12 years
    You 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
    Dan Bechard over 11 years
    I often use List<int> newList = oldList.ToList(). Same effect. However, Arkiliknam's solution is best for readability in my opinion.
  • supercat
    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
    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
    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
    supercat over 10 years
    If an Identity<T> was regarded as a reference to a T used to encapsulate identity only, and a MutableState<T> used to refer to one that encapsulates mutable state but not identity, a copy of a MutableState<List<Identity<T>>> should hold a reference to a new list with references to the same objects; a copy of a MutableState<List<MutableState<T>>> should hold a reference to a a new list with copies of the items therein.
  • Jeff Yates
    Jeff Yates over 10 years
    At 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
    raiserle over 10 years
    Quick! but: Why dirty?
  • Auguste Van Nieuwenhuyzen
    Auguste Van Nieuwenhuyzen about 10 years
    I just needed to be reminded of the first line - so I much prefer this answer, thanks @JeffYates!
  • IbrarMumtaz
    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
    Brandon Arnold over 9 years
    @IbrarMumtaz: That is the same as var clonedList = new List<string>(ListOfStrings);
  • Jonathon Cwik
    Jonathon Cwik over 9 years
    It'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
    Plutoz about 9 years
    Nice 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
    RandallTo almost 9 years
    This 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
    George Birbilis almost 9 years
    seems some collections (e.g. DataGrid's SelectedItems at Silverlight) skip the implementation of CopyTo which is a problem with this approach
  • Roman
    Roman almost 9 years
    I like nasty and dirty^^ It's like JSON.parse(JSON.stringify(obj)). Brilliant!
  • Tuukka Haapaniemi
    Tuukka Haapaniemi over 8 years
    Only negative aspect, if you can call it that, is that your classes have to be marked Serializable for this to work.
  • juharr
    juharr over 8 years
    I agree with @phoog, but If you think AddRange with Linq is less readable, then why not just use foreach. ForEach is harder to understand, harder to debug, and introduces closure semantics
  • Developer63
    Developer63 over 8 years
    This 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
    Seidleroni over 8 years
    I 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
    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
    Elliot Chen almost 8 years
    This is shallow copy.
  • Brian Ogden
    Brian Ogden almost 8 years
    @BrandonArnold you are wrong, what if T is an object, not value type?
  • Brandon Arnold
    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
    Brian Ogden almost 8 years
    Sorry @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
    Bernoulli Lizard over 7 years
    This does not work; changes to the values in the cloned array STILL change the values in the original list.
  • zainul
    zainul over 7 years
    you 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
    himanshupareek66 over 6 years
    Private members are not cloned using the JSON method. stackoverflow.com/a/78612/885627
  • Bence Végert
    Bence Végert over 6 years
    Do not forget the T should be serializable, otherwise you get System.Runtime.Serialization.SerializationException.
  • Mark G
    Mark G over 6 years
    A 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
    Matt about 6 years
    Good 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 like var b = a?.DeepClone(); (given var a = new List<string>() { "a", "b" }; for example).
  • ruffin
    ruffin about 6 years
    I 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 of oldList, though you want edits to elements shared. TL;DR: Maybe make shallow vs. deep use cases w/ ref types explicit.
  • mko
    mko over 5 years
    How is this a shallow copy?
  • kenno
    kenno over 4 years
    That'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
    ztorstri over 4 years
    Even 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
    Everts over 4 years
    Isn'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
    Nick Gallimore over 4 years
    @WellingtonZanelli Just confirmed that removing an element from myList removes it from cloneOfMyList as well.
  • NetMage
    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 list ToList calls new List<T> which ultimately will use Array.CopyTo, so about the same.
  • AH.
    AH. about 3 years
    I agree it is only half the answer as it is missing the IClonable part.
  • ToolmakerSteve
    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
    ToolmakerSteve almost 3 years
    There is a SERIOUS LIMITATION with this approach. Consider class StudentB : Student. In a list of Students, some might be StudentBs. new Student(s) will do the wrong thing - it will create a Student, not a StudentB. ICloneable does not have this limitation. (assuming StudentB also implements ICloneable.)
  • Alexandru Dicu
    Alexandru Dicu over 2 years
    This 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
    RBZ over 2 years
    I 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
    Preza8 over 2 years
    Serializing 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.