90

For example

List<string> name_list1 = new List<string>();
List<string> name_list2 = new List<string>();

later in the code:

name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");

name_list2 = name_list1; // I make a copy of namelist1 to namelist2

So, from this point I would like to keep adding element or making changes in name_list2 without affecting name_list1. How do I do that?

Liam
  • 27,717
  • 28
  • 128
  • 190
TheScholar
  • 2,527
  • 5
  • 23
  • 25

16 Answers16

187
name_list2 = new List<string>(name_list1);

This will clone the list.

Edit: This solution only works for primitive types. For objects, see other responses below.

sebastian.roibu
  • 2,579
  • 7
  • 37
  • 59
Inisheer
  • 20,376
  • 9
  • 50
  • 82
  • 2
    This is a nice, clean solution. Let me just add for clarification that if you do this, you shouldn't bother to initialize name_list2 with the `new List()` constructor a few lines above, as you'll be creating an object just to throw it away. Not a huge deal, but a bad coding habit to get into. – adv12 Nov 19 '12 at 03:44
  • 67
    this still references to name_list1 – DoIt Sep 23 '14 at 15:26
  • @Inisheer I was doing thi and it affected listExport after that listStructuresExport = new List(listExport); listStructuresExport.ForEach(val => val.term = SortTerm(val.term)); listStructuresExport.ForEach(val => val.term = ProcessTerms(val.term)); – DoIt Sep 23 '14 at 15:56
  • 34
    @Dev This only works with primitive types i.e list of strings. If you have a complex object then it won't work and you'll need to use deep cloning or create another list the same way you made the first. – Joshua Duxbury Sep 27 '16 at 10:20
  • 9
    This only works for primitive types indeed, it should be added to the question. – Zimano Oct 31 '16 at 14:18
  • Actually this worked for me with a list of my custom Object. How did it not work for you guys? – keshav.bahadoor Mar 15 '17 at 14:39
  • Yes none worked, only serialize and deserialize worked. – Muhammad Waqas Aziz Nov 14 '19 at 13:26
  • 1
    If you edited any elements at name_list2 that already in name_list1 , it will reflect the changes on both lists. this not accurate solution – VectorX Aug 16 '20 at 11:55
  • For complex object (Replace T with name of your Type name): list2 = list1.Concat(new List { object }).ToList(); – ali-myousefi Aug 24 '22 at 05:19
  • This solution work for simple list type(string list type ) not work for complex type like List then this is not work try this solution, it will work for all case https://stackoverflow.com/a/73631897/11827756 – Kalpesh Dabhi Sep 07 '22 at 07:55
14

Another Options is : Deep Cloning

public static T DeepCopy<T>(T item)
        {
            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream stream = new MemoryStream();
            formatter.Serialize(stream, item);
            stream.Seek(0, SeekOrigin.Begin);
            T result = (T)formatter.Deserialize(stream);
            stream.Close();
            return result;
        }

so,

you can use :

name_list2 = DeepCopy<List<string>>(name_list1);

OR:

name_list2 = DeepCopy(name_list1); 

will also work.

aru
  • 413
  • 4
  • 14
  • 4
    Nice solution but keep in mind that you always need to have the `Serializable` attribute on you class if it's a `reference type` – Jordy van Eijk Mar 30 '16 at 12:01
  • Yes.. You are right. This is most important point to keep in mind for deep cloning. – aru Apr 08 '16 at 04:53
  • 2
    even a tiny bit nicer if changed to `Clone(this T item)` so it can be called `name_list2=name_list1.Clone()` IMHO – Ole Albers May 19 '18 at 11:39
  • Where you define `DeepCopy` you will need to have `using System.Runtime.Serialization.Formatters.Binary;` for `BinaryFormatter` and `using System.IO;` for `MemoryStream` – Paul Masri-Stone Jul 08 '21 at 13:15
11

For Primitive Types you can do this:

List<string> CopyList = new List<string>(OriginalList);

For non-primitve/user-difined types you can do this:

List<Person> CopyList = new List<Person>();
foreach(var item in OriginalList)
{
    CopyList.Add(new Person { 
            Name = item.Name,
            Address = item.Address
    });
}
davinceleecode
  • 777
  • 3
  • 10
  • 31
5
name_list2 = new List<string>(name_list1); // Clone list into a different object

At this point, the two lists are different objects. You can add items to list2 without affecting list1

Dmitry Frenkel
  • 1,708
  • 11
  • 17
5

I like linq for this...

If list elements are primitives or structures then...

L2 = L1.ToList()

If list elements are classes then...

L2 = L1.Select(x => x.Copy()).ToList();

Where Copy could simply be a shallow copy exposure of MemberWiseClone, or it could be some implementation of a deep copy.

u8it
  • 3,956
  • 1
  • 20
  • 33
  • For me `L1.Select(x => x.Clone()).ToList();` worked. – Nilay Mehta Feb 04 '19 at 09:02
  • 1
    what is the .Clone()? – CDrosos Apr 08 '20 at 10:22
  • @CDrosos It's been a while since I last used C# at this point but my guess is that it's probably a class dependent implementation of ICloneable (https://learn.microsoft.com/en-us/dotnet/api/system.icloneable.clone?view=netframework-4.8) – u8it Apr 08 '20 at 19:48
  • You don't need the implementation of ICloneable, with the MemberWiseClone of LINQ you just have to create a Clone() method in the class you want to copy (https://stackoverflow.com/questions/8724421/how-to-get-a-copy-of-data-instead-of-a-reference-using-linq-lambda-in-c) – Matthew Aug 20 '21 at 07:32
4

The problem is the assignment. Until the assignment name_list2 = name_list1;, you have two different List objects on the heap pointed to by the variables name_list1 and name_list2. You fill up name_list1, which is fine. But the assignment says, "make name_list2 point to the same object on the heap as name_list1." The List that name_list2 used to point to is no longer accessible and will be garbage collected. What you really want is to copy the contents of name_list1 into name_list2. You can do this with List.AddRange. Note that this will result in a "shallow" copy, which is fine for the example you cite, where the list contents are strings, but may not be what you want when the list members are more complex objects. It all depends on your needs.

adv12
  • 8,443
  • 2
  • 24
  • 48
  • This answer explains what's going on a bit more than the others I've read so far, but I agree that the `name_list2 = new List(name_list1);` solution proposed by others is probably a cleaner way of actually doing the copy. – adv12 Nov 19 '12 at 03:39
4

Based on @Mrunal answer I created an extension method:

public static T Clone<T>(this T source)
    {
        // Don't serialize a null object, simply return the default for that object
        if (source == null)
        {
            return default;
        }

        // initialize inner objects individually
        // for example in default constructor some list property initialized with some values,
        // but in 'source' these items are cleaned -
        // without ObjectCreationHandling.Replace default constructor values will be added to result
        var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };

        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
    }

And you can call it like this:

L2 = L1.Select(x => x.Clone()).ToList();
sebastian.roibu
  • 2,579
  • 7
  • 37
  • 59
3

Here is an alternative solution:

    List<string> name_list1 = new List<string>();
    List<string> name_list2 = new List<string>();

    name_list1.Add("McDonald");
    name_list1.Add("Harveys");
    name_list1.Add("Wendys");

    name_list2.AddRange(name_list1.ToArray());

The ToArray() method copies 'name_list1' to a new array, which we then add to name_list2 via the AddRange() method.

A.Clymer
  • 472
  • 3
  • 9
3

I prefer Json converter method to serialize and deserialize, this way you don't have to mark the classes for serialization, especially you have numerous child classes.

https://www.newtonsoft.com/json/help/html/SerializingJSON.htm

1

For primitive types:
List ClonedList = new list(OriginalList);

For non-primitive/User Defined types:
We need to perform a deep copy: Deep Copy is used to make a complete deep copy of the internal reference types, for this we need to configure the object returned by MemberwiseClone().

Step1- In your class inherit from ICloneable:
public class MyClass:ICloneable

Step2- Implement method

public MyClass Clone()
{
  MyClass MyClassObj =new MyClass();
  MyClassObj.Property1 = this.Property1;
  .
  .
  MyClassObj.Property_N = this.Property_N;
  return MyClass;
}

Step3- now clone your List

List<MyClass> MyClassClone = new List<MyClass>(); 
for(i=0; i<Count; i++)
  {
      MyClassClone.Add(OriginalClaaObj[i].Clone());
  }

This will make deep copy of each item of the object.

Palash Roy
  • 1,547
  • 1
  • 15
  • 11
0

None of the above solutions worked for me when using lists of class objects.

This can be used for copying any object to another object with shared property names.

public static void ObjectToObject(object source, object destination)
{
  // Purpose : Use reflection to set property values of objects that share the same property names.
  Type s = source.GetType();
  Type d = destination.GetType();

  const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;

  var objSourceProperties = s.GetProperties(flags);
  var objDestinationProperties = d.GetProperties(flags);

  var propertyNames = objSourceProperties
  .Select(c => c.Name)
  .ToList();

  foreach (var properties in objDestinationProperties.Where(properties => propertyNames.Contains(properties.Name)))
  {

    try
    {
      PropertyInfo piSource = source.GetType().GetProperty(properties.Name);

      properties.SetValue(destination, piSource.GetValue(source, null), null);
    }
    catch (Exception ex)
    {
      throw;
    }

  }
}


public static List<T> CopyList<T>(this List<T> lst)
{
  List<T> lstCopy = new List<T>();

  foreach (var item in lst)
  {
    var instanceOfT = Activator.CreateInstance<T>();
    ObjectToObject(item, instanceOfT);
    lstCopy.Add(instanceOfT);
  }
  return lstCopy;
}

For lists use this: list2 = list1.CopyList();

  • Please add some description of what the code does so people reading the answer in the future can follow your solution. – Adam B Sep 27 '18 at 15:11
0

If both the lists are of the same complex type then you can do something like below:-

SomeClass List2 = new List();

List1.ForEach(u => List2.Add(u));

What I am doing is to loop through each element of List1 and keep adding it to List2. I believe this is the shortest way to do it.

ASHWANI KUMAR
  • 71
  • 1
  • 9
  • A simple test shows that this too is by reference. Change one list and the other list is also changed. – Matthew Jan 11 '22 at 18:36
0

While it could be potential performance-threat solution, but it would copy the values property-by-property eloquently.

using Newstonsoft.Json;

ClassA classA = new ClassA();
ClassA classACopyWithoutReference = JsonConvert.DeserializeObject<ClassA>(JsonConvert.SerializeObject(classA));
Ashokan Sivapragasam
  • 2,033
  • 2
  • 18
  • 39
0

this solution works For complex objects (Replace T with name of your Type):

list2 = list1.Concat(new List<T> { object }).ToList();

or:

list2 = list1.ToArray().Append(object).ToList()
ali-myousefi
  • 822
  • 2
  • 11
  • 26
0

You can clone the complex object by serialize and deserialize it, it will remove you object reference and create new object without reference

using Newstonsoft.Json;

List<string> name_list1 = new List<string>();
name_list1.Add("McDonald");
name_list1.Add("Harveys");
name_list1.Add("Wendys");

name_list2 = name_list1; 

List<string> name_list2 = JsonConvert.DeserializeObject<List<string>> 
(JsonConvert.SerializeObject(name_list1)); // Ii make a copy of namelist1 to namelist2
Kalpesh Dabhi
  • 760
  • 8
  • 18
-1

this is working for me using LINQ...

lst1= lst2.ToList();
Gzant
  • 1
  • Are you sure that this is not a reference to the original list? – Ryanman May 14 '21 at 14:24
  • This does not work. It is a reference to the original list. Make a change in one list and it is reflected in the other list too. – Matthew Jan 11 '22 at 18:29