Deep copy Vs Shallow Copy in .NET

Prafull RanjanTechnical Lead
Published:
Copy of an Object :
In today’s object oriented programming world, Object's are basic medium to represent real world entities. So through this practice, sometimes it becomes obvious to interchange or exchange information or even we can say, pass these objects information between different processes.

Well, To perform these kind of activities It is required that we will create copy of objects and pass it using available medium so that same information will become available to another side.

There are more than a few different ways exists to copy an object, among them we will explore two and they are Deep copy and Shallow Copy.

Shallow Copy : Shallow copy approach creates a new instance of the original object with similar nature, I mean same type, and then starts copying the original objects information or more specifically we can say its nonstatic  data members. While copying data member. It follows two different mechanism. If the data member is a value type (struct, basic data types etc), a bit-by-bit copy will be performed and If the field is a reference type(Class, collections etc), then simply reference is copied leaving referred object’s data. Therefore, As a result the reference in the original object and the reference in the copy object will point to the same object.

Deep copy: Deep copy approach completely interrogates the original object and copies everything irrespective of value type or reference type. Therefore a deep copy of an object will bring you, an object with all of the elements duplicated from the original object but not pointing to the source object. I mean, A deep copy of an object duplicates everything directly or indirectly referenced by the fields in the object.

-Well, sometimes definitions bring us to a puzzled situation where we found ourselves bit confused. So need to get this concept step by step, I’m sure by this way we will be able to explore it more and more.

Moving two steps forward with Shallow and Deep copy:
Step 1: In first approach we will try to get it through pictures and graphs, as I think through this way it will become easy to understand it..
-Consider two objects, A and B, which each refer to two separate memory blocks as shown in Fig - 1
H1.JPG
For Shallow copy, We can say while copying A into B, Simply we are trying to attach B to the same memory block as A. Fig - 2
 H2.JPG

“Be careful while getting it, as we are copying A to B, I mean neither we are trying to copy the address nor we are in the process of paasing the reference.” Simply we are in the process of copying Object A’s data into B. This results in a situation in which some data is shared between A and B as represented in Fig - 3.
H3.JPGThus modifying the any one will alter the other. The original memory block of B is now no longer referred from anywhere.
For deep copy while coping A into B, we are in the process of copy data actually as shown in Fig - 4.
 H4.JPGAs a result we will have, A with original data in separate memory block (earlier) and B will have A’s duplicate data in separate memory block as shown in Fig - 5.
H5.JPG
Step 2: In another approach we will try to get it by implementing it using C# :
For the implementation, let’s create a console application “ShallowVsDeepCopyPrj” and create two separate classes Product and ProductCatalog, in both classes I have implemented ICloneable interface.

namespace ShallowVsDeepCopyPrj
                      {
                          public class Product : ICloneable
                          {
                              private String m_ProductName, m_ProductDesc;
                              private String prodName = "ABC of C#";
                              private ProductCatalog m_ProductCatalog = new ProductCatalog("ABC of C#", "AVAILABLE");
                              public Product()
                              {
                                  this.Setm_ProductDesc = "Test Your C# Skill";
                                  this.Setm_ProductName = prodName;
                              }
                              public String Setm_ProductDesc { set { m_ProductDesc = value; } get { return m_ProductDesc; } }
                              public String Setm_ProductName { set { m_ProductName = value; } get { return m_ProductName; } }
                              public ProductCatalog Setm_ProductCatalog { set { m_ProductCatalog = value; } get { return m_ProductCatalog; } }
                              Object ICloneable.Clone() { return this.Clone(); }
                      
                              public virtual Product Clone()
                              {
                                  // Start with a flat, Simply Memberwise copy 
                                  Product shallowCopy_Prod = this.MemberwiseClone() as Product;
                                  return shallowCopy_Prod;
                              }
                      
                              public Product CloneThroughShallowCopy()
                              {
                                  return this.Clone(); //Return Shallow Copy
                              }
                      
                              public virtual Product CloneThroughDeepCopy()
                              {
                                  // Start with a flat,Creating seperate memory block for reference type members
                                  Product deepCopy_Prod = new Product();
                      
                                  // Then deep-copy everything that needs the - special attention
                                  deepCopy_Prod.Setm_ProductName = this.Setm_ProductName;
                                  deepCopy_Prod.Setm_ProductDesc = this.Setm_ProductDesc;
                                  deepCopy_Prod.Setm_ProductCatalog = this.Setm_ProductCatalog.ClonedThroughDeepCopy();
                      
                                  return deepCopy_Prod;
                              }
                          }
                      
                          public class ProductCatalog : ICloneable
                          {
                              private String m_ProductName, m_ProductStatus;
                      
                              public ProductCatalog()
                              {
                                  //Do nothing     
                              }
                              public ProductCatalog(string pName, string pCat)
                              {
                                  this.Setm_ProductName = pName;
                                  this.Setm_ProductStatus = pCat;
                              }
                      
                              public String Setm_ProductStatus { set { m_ProductStatus = value; } get { return m_ProductStatus; } }
                              public String Setm_ProductName { set { m_ProductName = value; } get { return m_ProductName; } }
                      
                              Object ICloneable.Clone() { return this.Clone(); }
                      
                              public virtual ProductCatalog Clone()
                              {
                                  // Start with new ProductCatalog object
                                  ProductCatalog deepCopy_ProdCat = new ProductCatalog();
                      
                                  // Then deep-copy everything that needs the - special attention
                                  deepCopy_ProdCat.Setm_ProductName = this.Setm_ProductName;
                                  deepCopy_ProdCat.Setm_ProductStatus = this.Setm_ProductStatus;
                                  return deepCopy_ProdCat;
                              }
                      
                              public ProductCatalog ClonedThroughDeepCopy()
                              {
                                  return this.Clone();
                              }
                          }
                      }

Open in new window


-Now implementing these two class in main thread :
 static void Main(string[] args)
                              {
                                  Product m_Product = new Product();
                                  try 
                                  {
                                      Product ShallowCopyProd = (Product)m_Product.CloneThroughShallowCopy(); // Shallow Copy of Product
                                      Product DeepCopyProd = (Product)m_Product.CloneThroughDeepCopy();//Deep Copy of Product
                      
                                      //Making some changes to m_Product, let's se where it gets reflected and where it is not reflecting
                                      m_Product.Setm_ProductName = "XYZ";
                                      m_Product.Setm_ProductDesc = "XYZ1";
                                      m_Product.Setm_ProductCatalog.Setm_ProductName = "UNKNOWN";
                                      m_Product.Setm_ProductCatalog.Setm_ProductStatus = "NA";
                      
                                      Console.WriteLine("\n");
                                      Console.WriteLine("Output - Shallow Copy Vs Deep Copy in .NET: ");
                                      Console.WriteLine("Source - Product: " + m_Product.Setm_ProductName + "/" + m_Product.Setm_ProductDesc + "/" + m_Product.Setm_ProductCatalog.Setm_ProductName + "/" + m_Product.Setm_ProductCatalog.Setm_ProductStatus);
                                      Console.WriteLine("Shallow Copy - Product: " + ShallowCopyProd.Setm_ProductName + "/" + ShallowCopyProd.Setm_ProductDesc + "/" + ShallowCopyProd.Setm_ProductCatalog.Setm_ProductName + "/" + ShallowCopyProd.Setm_ProductCatalog.Setm_ProductStatus);
                                      Console.WriteLine("Deep Copy - Product: " + DeepCopyProd.Setm_ProductName + "/" + DeepCopyProd.Setm_ProductDesc + "/" + DeepCopyProd.Setm_ProductCatalog.Setm_ProductName + "/" + DeepCopyProd.Setm_ProductCatalog.Setm_ProductStatus);
                                      Console.ReadLine();
                                  } 
                                  catch (Exception ex) { 
                                   Console.WriteLine(ex.Message.ToString()); }
                              }

Open in new window


Will bring you output:
Output - Shallow Copy Vs Deep Copy in .NET:
Source - Product: XYZ/XYZ1/UNKNOWN/NA
Shallow Copy - Product: ABC of C#/Test Your C# Skill/UNKNOWN/NA
Deep Copy - Product: ABC of C#/Test Your C# Skill/ABC of C#/AVAILABLE

-By analysing bold font in the output we can say that,shallow copy reflected the change's in the source but deep copy doesn't.
As of now we are through the deep copy and shallow copy basics,I mean what they are and how they are different.

Advantages / Disadvantages:
The advantage of shallow copies is that their execution speed is fast and does not depend on the size of the data but data will be shared with original object while deep copies do not depends on each other (Original and deep copies) but at the cost of slower more expensive copy.

So it become an obvious question that when we should go for deep copy and when for shallow copy, let's have a try:
-If Object has been consist of more reference type members. In that case shallow copy will be not effective and deep copy will be a good option.
-If you have object which consist of simple data type members(value type), In that case shallow copy will be a good option as it is fast and less expensive in terms of memory.

----------------------------------------------------------------------------------------------------------------------------------------------------------------
In this article I just tried to explain the shallow copy and deep copy basic concepts, difference between them and their implementation, For the implementation part I'll  say there are many and many examples and different ways are possible to explain these concepts but I tried the simplest one [ as time is a big factor :) ].

Even while creating deep copy you can go for serialization with your own formatters and for shallow copy Memberwiseclone.
For deep copy you should be very careful towards your requirement, I mean you need to be sure of what you want, i.e you want a deep copy for same object type or more than one object type.
Try to explore this concepts by using more real time scenario's, I'm sure It will become much more easier to understand.

I hope this article will be of some use.  
0
4,900 Views

Comments (0)

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.