My two cents on Deep copy vs Shallow copy in .Net

Learn how deep copy and shallow copy can be used to create a clone of an object in .Net

Object cloning in .NET

Object cloning in .NET

Microsoft .Net provides support for cloning objects -- an ability to create an exact copy of an object (also known as a clone). Cloning can be of two types: shallow copy and deep copy. While the former can be implemented by making a call to the MemberwiseClone method of the System.Object class, implementing the latter is a bit tricky as you don't have support for it in the framework by default. In essence, while a shallow copy copies the references sans the referenced objects, a deep clone creates a copy of the source object together with its references.

What are all the available options for cloning?

To clone an instance of a class in C#, you have a few options to choose from. These include the following:

  • Using the System.Object.MemberwiseClone method to perform a shallow copy
  • Using Reflection by taking advantage of the Activator.CreateInstance method
  • Using Serialization
  • By implementing the IClonable interface

Note that when cloning objects or instances of classes in .Net, you need not consider static members or static fields. The reason is that static objects are stored in a shared memory location and you have one memory location allocated for them per application domain.

Shallow copy vs. deep copy

Consider a class Employee and that we create an instance of the Employee class as shown below.

Employee emp = new Employee();

Employee clone = emp;

Refer to the code snippet above. The assignment operator "=" would copy the reference and not the actual object. The MemberwiseClone() method defined in the System.Object class does exactly the same thing. These are examples of shallow copy. Hence when you use an assignment operator to copy and object to another or, use the Memberwise.Clone() method, you are actually doing a shallow copy of the object.

While in shallow copy the members of the copied object refer to the same object as the original object, in a deep copy, separate instances of each of the reference type members in the original instance is created in the new or cloned instance. Hence if you have a reference type in the original instance, the new instance will also contain the same reference type member in it but this reference type will point to an altogether new instance.

In shallow copy, a new object is created and then the non-static members of the source object is copied to the target object or the new object. If the member is a value type field then a bit by bit copy of the field is performed. In contrast, if the member being copied is a reference type, the reference is copied. Hence, the reference member inside the original object and the target objects refer to the same object in the memory.

If you have a collection with individual elements inside and you would want to perform a shallow copy the collection instance. It should be noted that a shallow copy of a collection instance copies the structure of the collection but not the elements inside the collection. Hence, after you perform a shallow copy of the collection instance, you would have two collections sharing the individual elements of the collection. On the contrary, if you perform a deep copy of the collection instance, you would have two collection instances with the individual elements of the original collection duplicated.

Implementing deep copy using serialization

You can implement deep copy in many ways. One of the most preferred ways to implement a deep copy of an object is by using serialization. You can also leverage reflection to perform a deep copy of an instance of a class. The following code snippet illustrates how you can write a method that implements binary serialization to perform a deep copy of an instance using C#.

public static T DeepCopy<T>(T obj)

       {

           if (!typeof(T).IsSerializable)

           {

               throw new Exception("The source object must be serializable");

           }

           if (Object.ReferenceEquals(obj, null))

           {

               throw new Exception("The source object must not be null");

           }

           T result = default(T);

           using (var memoryStream = new MemoryStream())

           {

                var formatter = new BinaryFormatter();

               formatter.Serialize(memoryStream, obj);

               memoryStream.Seek(0, SeekOrigin.Begin);

               result = (T)formatter.Deserialize(memoryStream);

               memoryStream.Close();

           }

           return result;

       }

Considering that you have an entity class called Employee, you can perform a deep copy of an instance of the Employee class as shown in the code snippet below.

static void Main(string[] args)

       {

           Employee emp = new Employee();

           emp.EmployeeId = 1;

           emp.FirstName = "Joydip";

           emp.LastName = "Kanjilal";

           Employee clone = DeepCopy<Employee>(emp);

           if(Object.ReferenceEquals(emp, clone))

           {

               Console.WriteLine("References are the same.");

           }

           else

           {

               Console.WriteLine("References are different.");

           }

       }

When you execute the above program, a deep copy of the instance "emp" would be performed and the message "References are different." will be displayed.

This article is published as part of the IDG Contributor Network. Want to Join?

From CIO: 8 Free Online Courses to Grow Your Tech Skills
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.