Monday, August 9, 2010

Cloning a generic List<T>

Today we had to do a copy operation on a generic list to accomplish a business logic on our server. The situation was such that we had retrieved some data from the database and then store it in a List<T> which was on our corporate servers. Based on a formula we had to remove some elements from the list , a copy of the original collection should be persisted so in case of any error/exception the original data can be resorted.

You might already knows how to implement IClonable interface but for those who are not aware, I will explain the method to clone the generic list.
To make a copy of generic list we need to perform this steps

1) Derive our data class from IClonable
2) Implement the members of IClonable
3) Write a extension method .on List<T>

IClonable is the way C# implements the copy constructor the basic fundamental is to create a copy of the object . The System.ICloneable interface defines a method of create a new instance of a class with the identical value as an existing instance. There are two ways of cloning

1) Shallow Cloning – all objects are copied but only link of the referred objects are copied
2) Deep Cloning- all the object are copied along with the referred objects

shallow_cloning

The above figure describes a shallow copy of objects looks in memory, we have a class object called DataClassObj1containing two objects which we call as the ContainingObject. In the second part of the figure we have another object DataClassObj2 which is a shallow copy of DataClassObj1. DataClassObj1 and DataClassObj2 are having reference to same object, so changes made through any of the DataClassObj will be reflected in the other on the other hand if it was a deep copy then both the objects would have their individual ContainingObjects and changes made in one would not be reflected in the other.

A shallow copy is by far the easiest way to clone your class, shallow copy in .net can be done by MemberwiseCloning and every object inherited from Object class can use this method to get a shallow clone. Below is the sample code illustrating how to use ICloneable and MeberwiseClone();

  1:    [Serializable]
  2:     public class ContainingObject
  3:     {
  4:         public string sName;                
  5:     }
  6: 
  7:     [Serializable]
  8:     public class DataClass:ICloneable
  9:     {
 10:         
 11:         public ContainingObject ContainingObject1;
 12:         public ContainingObject ContainingObject2;
 13: 
 14:         public DataClass()
 15:         {
 16:             ContainingObject1 = new ContainingObject();
 17:             ContainingObject2 = new ContainingObject();
 18:         }
 19:         public object Clone()
 20:         {
 21:             return MemberwiseClone();
 22:         }
 23:     }

Now the problem with shallow cloning is that if you change a reference object in the clone the original reference is also changed. for example in below line of code when the line 4 is executed both d1.ContainingObject1.sName and d1.ContainingObject1.sName are changed to “Amin”.

  1: DataClass d1 = new DataClass();
  2: d1.ContainingObject1.sName = "Vikas";
  3: DataClass d2 = d1.Clone() as DataClass;
  4: d2.ContainingObject1.sName = "Amin";



For a deep cloning of the object we can use below extension method that will deep copy any object

  1:   using System.IO;
  2:     using System.Runtime.Serialization.Formatters.Binary;
  3:     public static class DeePCloneExtensionMethod
  4:     {
  5:         public static T DeepClone<T>(this T a)
  6:         {
  7:             using (MemoryStream stream = new MemoryStream())
  8:             {
  9:                 BinaryFormatter formatter = new BinaryFormatter();
 10:                 formatter.Serialize(stream, a);
 11:                 stream.Position = 0;
 12:                 return (T)formatter.Deserialize(stream);
 13:             }
 14:         }
 15:     }

1 comment: