C# - How to clone a generic List

(Using 7 different techniques)

Assume we have a generic List of objects of type CWebPage. The CWebPage class contains a System.Uri object (a reference type) and an integer Count (a value type).


  class CWebPage
  {
      public Uri Uri; // E.g. http://www.google.com
      public int Count; // E.g. 10
  }
  
  var list = new List<CWebPage>();
  
1
We can create a shallow copy of the list, using the parameterized List constructor List(IEnumerable<T> collection).

  var copy = new List<CWebPage>(list);
  

A shallow copy is useful if we want to sort the list. In that case we specifically don't want a deep copy. We don't want to duplicate the list items, only the list object and the reference variables that point to them.


  copy.Sort(delegate (CWebPage left, CWebPage right)
  {
      return left.Uri.Host.CompareTo(right.Uri.Host);
  });
  
2
We can create a deep copy of the list, using a foreach loop and the ICloneable method Clone.

  var copy = new List<CWebPage>();
  
  foreach(var elt in list)
  {
      copy.Add((CWebPage)elt.Clone());
  }
  

Implementing ICloneable on CWebPage.


  class CWebPage : ICloneable
  {
      public Uri Uri;
      public int Count;
  
      // This is a deep copy implementation of Clone
      public object Clone()
      {
          return new CWebPage
          {
              Uri = new Uri(this.Uri.OriginalString),
              Count = this.Count,
          };
      }
  }
  

3
We can create a deep copy of the list, using the List method List<T>.ForEach and the ICloneable method Clone (as implemented in 2).

  var copy = new List<CWebPage>();
  
  list.ForEach(delegate (CWebPage page)
  {
      copy.Add((CWebPage)page.Clone());
  });
  

Ads by Google

4
We can create a deep copy of the list, using the List method ConvertAll and the ICloneable method Clone (as implemented in 2).

  var copy = list.ConvertAll(elt => elt.Clone());
  
5
We can create a deep copy of the list, using the Linq method Enumerable.Select and the ICloneable method Clone (as implemented in 2).

  var copy = list.Select(elt => elt.Clone()).ToList();
  
6
We can create a deep copy of the list by serializing it to a stream, and deserializing the stream to create a new instance of the list.

We first need to implement the interface ISerializable on our CWebPage class.


  class CWebPage : ISerializable
  {
      public Uri Uri;
      public int Count;
  
      // read from stream
      private CWebPage(SerializationInfo info, StreamingContext context)
      {
          this.Uri = (Uri)info.GetValue("Uri", typeof(Uri));
          this.Count = info.GetInt32("Count");
      }
  
      // save to stream
      public void GetObjectData(SerializationInfo info, StreamingContext context)
      {
          info.AddValue("Uri", this.Uri);
          info.AddValue("Count", this.Count);
      }
  }
  

A small utility function encapsulates the calls to Serialize and Deserialize:


  public static T CopyUsingSerializer(T obj)
  {
      using (var ms = new MemoryStream())
      {
          var formatter = new BinaryFormatter();
          formatter.Serialize(ms, obj);
          ms.Position = 0;
 
          return (T)formatter.Deserialize(ms);
      }
  }
 

We can now create a deep copy of the list using ISerializable by calling CopyUsingSerializer.


  var copy = CopyUsingSerializer(list);
 
7
We can create a deep copy of the list, using any third party library that supports serialization. E.g. Newtonsoft JSON.

  string serialized = JsonConvert.SerializeObject(list);
  var copy = JsonConvert.DeserializeObject<List<CWebPage>>(serialized);
  

The serialized string (JSON text) looks like this:

  [
      {"Uri":"http://www.google.com","Count":10},
      {"Uri":"http://www.yahoo.com","Count":20},
      {"Uri":"http://www.bing.com","Count":30}
  ]
  

Ads by Google

Ask a question, send a comment, or report a problem - click here to contact me.

© Richard McGrath