Object Cloning, ICloneable, Deep and Shallow Copies [C#]

Hello World,

One fine day, a colleague of mine wanted me to explain Cloning with respect to Deep and Shallow copies and when the ICloneable interface should be used. As this is not something one encounters everyday, I got down to revising my understanding of the concepts and thought it would be nice if I document my understanding for future reference – so here it goes!

We’ve been there

Let’s say you have an object that is mutable within the current scope, but you’d somehow want to retain a copy of this object in it’s original state. How would you go about doing this? Before it gets too abstract, let’s take this simple employee object as the one we are working with:

public class Employee
{
 public int Id { get; set; }
 public string Name { get; set; }
 public int Age { get; set; }
 public override string ToString()
 {
    return string.Format("Id: {0}, Name: {1}, Age: {2}", Id, Name, Age);
 }
}

Now, if we declare a new Employee variable and just equate the references, we would have two references to the same object like so:

void Main()
{
 var emp1 = new Employee {Id=1,Name="Jane Begood",Age=21};
 Console.WriteLine("Original Object {0}", emp1);
 
 var emp1Ref = emp1;
 emp1Ref.Age = 25;

 Console.WriteLine("After modifying reference, original object: {0}", emp1);
}

So modifying the reference also modified the original object – but what we needed is that the copy of the object should be on it’s own and not change or be changed by any modifications to the original object.

A poor-man’s implementation could create a new Employee object and then copy each property one by one like so:

void Main()
{
 var emp1 = new Employee {Id=1,Name="Jane Begood",Age=21};
 Console.WriteLine("Original Object {0}", emp1);
 
 var emp1Ref = new Employee { Id=emp1.Id,Name=emp1.Name,Age=emp1.Age };
 emp1Ref.Age = 25;
 Console.WriteLine("After modifying reference, original object: {0}", emp1);
}

As can be seen, now emp1Ref  is a separate object. This approach would work well for simple objects but starts getting messy with complex objects. This is where Cloning comes to our rescue.

Before delving into the matter any further, let’s review the concept of Deep and Shallow copies.

Shallow Copy

MSDN defines a shallow copy as “The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object“.

The thing to note is that the MemberwiseClone method works on an instance of an object.

Deep Copy

A deep copy, again as explained in the referred link from MSDN creates an entirely new object that is identical to the original object but has no reference to the original object.

The (very) important question

Now, the whole purpose of this post is to find out how one should implement a deep copy. As is the case with any other topic in .NET, there are myriad ways of achieving this, each having pros, cons and typical use cases when the specific method should be used. Let’s start with the simplest of ways using our Employee class. The class has now been modified to give it the capability to do a shallow and deep copy of itself:

public class Employee
{
 public int Id { get; set; }
 public string Name { get; set; }
 public int Age { get; set; }
 public override string ToString()
 {
    return string.Format("Id: {0}, Name: {1}, Age: {2}", Id, Name, Age);
 }
 
 public Employee ShallowCopy()
 {
    return (Employee)this.MemberwiseClone();
 }
 
 public Employee DeepCopy()
 {
    Employee emp = (Employee)this.MemberwiseClone();
    return emp;
 }
}

As evident, this method of deep copying is simple, but would quickly become cumbersome for more complex objects. This Stackoverflow discussion proposes a solution that is readable yet suitable for complex scenarios. in summary, you create an extension method like so:

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
 /// <summary>
 /// Perform a deep Copy of the object.
 /// </summary>
 /// <typeparam name="T">The type of object being copied.</typeparam>
 /// <param name="source">The object instance to copy.</param>
 /// <returns>The copied object.</returns>
 public static T Clone<T>(this T source)
 {
    if (!typeof(T).IsSerializable)
    {
      throw new ArgumentException("The type must be serializable.", "source");
    }

    // Don't serialize a null object, simply return the default for that object
    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);
    }
 }
}

There are a couple of constraints to using this: 1) To use this method, the object must be Serializable and 2) Since it involves serialization, there would be a performance penalty (which the author acknowledges). However, if this is a one off operation that does not need to be used too frequently, we can safely ignore the performance impact.

The ICloneable interface

So now, most of us would’ve seen the ICloneable interface with a Clone method. Question is, why not use that as the basis of a type that offers cloning and just implement the Clone as per our scenario?

If one looks closely, a type that implements ICloneable gives no guarantee as to which type of cloning is being offered (deep or shallow). In other words, this is a loose contract and is generally a bad idea as discussed here.

Summary

In conclusion, to implement an apt cloning mechanism, the factors to consider would be (IMHO)

  1. Do you need a Deep or Shallow Copy?
  2. How frequently (and why? – design-wise) would you need to clone?
  3. Is your type serializable?

This is an advanced topic, so there may be more facts that I may have missed out on. I’ll try to revisit the post as soon as I find something relevant to add.

Until then, Happy Coding!

Advertisements
Tagged with: ,
Posted in Uncategorized

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

  • Comic for July 25, 2017
    Dilbert readers - Please visit Dilbert.com to read this feature. Due to changes with our feeds, we are now making this RSS feed a link to Dilbert.com.
%d bloggers like this: