Monday, November 28, 2005 - Posts

How to: Deep copy any serializable object

Since most types in the .NET framework and in the class libraries you develop yourself are reference types, assigning one instance to another would have the two pointing to the same object. Because of this, the need to clone object is quite common within .NET applications. Out of the box, System.Object has a MemberwiseClone method which creates a shallow copy of the object. A shallow copy is a copy of the class members without copies of objects further down in the object graph. You can implement the IClonable interface, which defines a Clone method, to explicitly support deep cloning of your classes, but still client code has no guarantee that a class implementing the ICloneable interface creates a deep clone of an instance.
If you have a large class library, such as a domain model, implementing ICloneable will require much work and you’ll also have to ensure that your cloning algorithm functions as intended whenever you change your class. An option that I’ve seen many developers resort to is to use reflection to generalize the cloning algorithm. Reflection has some overhead, but it isn’t as slow as many people think. How ever, if you find the performance overhead of using reflection acceptable, there is a much easier and simpler way to deep clone an object.

As long as your types are serializable, you can use serialization to clone the object. Below is an example of a method that creates a deep clone of an object by serializing the instance to a MemoryStream, and then creates a cloned object by deserializing the stream to a new instance.
public static class XeroxMachine
{
   
public static T Clone<T>(T source)
    {
             
if (!typeof(T).IsSerializable)
              {
                    
throw new ArgumentException("The type must be serializable.","source");
              }
       
if (Object.ReferenceEquals(source, null))
        {
           
return default(T);
        }
        IFormatter formatter =
new BinaryFormatter();
        Stream stream =
new MemoryStream();
       
using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(
0, SeekOrigin.Begin);
           
return (T) formatter.Deserialize(stream);
        }
    }
}

Generics don’t have a way of restricting a generic type parameter to be serializable, therefore I’m checking asserting that the type is serializable before I clone it.
By using the XeroxMachine helper class, the ICloneable interface is a breeze to implement.

[Serializable]
public
class MyClass : ICloneable
{
      
public object Clone()
       {
             
return XeroxMachine.Clone(this);
       }
}

This technique works for every serializable type, and you’re guaranteed to get a true, deep copied clone of the object. Cloning an object this way is of course less efficient in terms of performance than writing your own type specific Clone method, but it is much more efficient when it comes to the time it takes to write the code.