Author : Rahul
Last Modified : 10-Oct-2021
Complexity : Beginner

Deep Copy and Shallow Copy in C#


When we copy one object into another using c#, the compiler works differently for value type and reference type object.
If our object is a value type, a simple value is copy and the original object and cloned object point to different memory locations. If we change one object value, another object value is not changed.
If our object is a reference type, the reference is copied and the original object and cloned object point to the same memory location. If we change one object value, another object value is also changed.

Example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ShallowCopyDeepCopy
{
   class Program
   {
       static void Main(string[] args)
       {
           //Original Employee
           Employee originalEmployee = new Employee(1, 100, "Rahul");
           
           //Cloned Employee
           Employee clonedEmployee = originalEmployee;
           
           //Before Changing Cloned Employee
           Console.WriteLine("Before Changing in Cloned Employee:");
           Console.WriteLine("Original Employee:");
           Console.WriteLine($"Employee Id:{originalEmployee.EmployeeId}, Employee Name:{originalEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{originalEmployee.EmployeeDetails.EmployeeSalary}");
           Console.WriteLine("Cloned Employee:");
           Console.WriteLine($"Employee Id:{clonedEmployee.EmployeeId}, Employee Name:{clonedEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{clonedEmployee.EmployeeDetails.EmployeeSalary}");
           
           //Update Cloned Employee
           clonedEmployee.EmployeeId = 2;
           clonedEmployee.EmployeeDetails.EmployeeName = "Rahul New";
           clonedEmployee.EmployeeDetails.EmployeeSalary = 200;
           
           //After Changing Cloned Employee
           Console.WriteLine("After Changing in Cloned Employee:");
           Console.WriteLine("Original Employee:");
           Console.WriteLine($"Employee Id:{originalEmployee.EmployeeId}, Employee Name:{originalEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{originalEmployee.EmployeeDetails.EmployeeSalary}");
           Console.WriteLine("Cloned Employee:");
           Console.WriteLine($"Employee Id:{clonedEmployee.EmployeeId}, Employee Name:{clonedEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{clonedEmployee.EmployeeDetails.EmployeeSalary}");
           
           Console.ReadLine();
       }
   }
   
   /// <summary>
   /// Employee Class
   /// </summary>
   public class Employee
   {
       public int EmployeeId { get; set; }
       public EmployeeDetail EmployeeDetails { get; set; }
       
       /// <summary>
       /// Constructor
       /// </summary>
       /// <param name="id">id</param>
       /// <param name="salary">salary</param>
       /// <param name="name">name</param>
       public Employee(int id, int salary, string name)
       {
           EmployeeId = id;
           EmployeeDetails = new EmployeeDetail(salary, name);
       }
   }
   
   /// <summary>
   /// Employee Detail Class
   /// </summary>
   public class EmployeeDetail
   {
       public string EmployeeName { get; set; }
       public int EmployeeSalary { get; set; }
       
       /// <summary>
       /// Constructor
       /// </summary>
       /// <param name="salary">salary</param>
       /// <param name="name">name</param>
       public EmployeeDetail(int salary, string name)
       {
           EmployeeName = name;
           EmployeeSalary = salary;
       }
   }
}

Output

Before Changing in Cloned Employee:
Original Employee:
Employee Id:1, Employee Name:Rahul, Employee Salary:100
Cloned Employee:
Employee Id:1, Employee Name:Rahul, Employee Salary:100

After Changing in Cloned Employee:
Original Employee:
Employee Id:2, Employee Name:Rahul New, Employee Salary:200
Cloned Employee:
Employee Id:2, Employee Name:Rahul New, Employee Salary:200

Explanation

In the above example, we are doing normal copy.
Since whole object reference is copied into cloned object, so if we changed any value into cloned object, original object value will also be updated. 
For Employee Id, Here we are changing Employee Id to 2 in cloned object and Employee Id is also updated to 2 in original object.
For Employee Detail, Here we are changing Employee Name to Rahul New in cloned object and Employee Name is also updated to Rahul New in original object.

There are two ways to create a clone object. These two ways are as follow:

  1. Shallow Copy
  2. Deep Copy

Now we will discuss both ways one by one.

Shallow Copy

Shallow copy is used to create the cloned object by using the original object. In this type of copy, If a field is a value type, the value will be copied into the cloned object and If a field is a reference type, a reference will be copied but the referred object will not be copied. So the original object and its clone refer to the same object.
In C#, MemberwiseClone() method is used for Shallow Copy.

Example

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ShallowCopyDeepCopy
{
   class Program
   {
       static void Main(string[] args)
       {
           //Original Employee
           Employee originalEmployee = new Employee(1, 100, "Rahul");
           
           //Cloned Employee
           Employee clonedEmployee = (Employee)originalEmployee.ShallowCopy();
           
           //Before Changing Cloned Employee
           Console.WriteLine("Before Changing in Cloned Employee:");
           Console.WriteLine("Original Employee:");
           Console.WriteLine($"Employee Id:{originalEmployee.EmployeeId}, Employee Name:{originalEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{originalEmployee.EmployeeDetails.EmployeeSalary}");
           Console.WriteLine("Cloned Employee:");
           Console.WriteLine($"Employee Id:{clonedEmployee.EmployeeId}, Employee Name:{clonedEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{clonedEmployee.EmployeeDetails.EmployeeSalary}");
           
           //Update Cloned Employee
           clonedEmployee.EmployeeId = 2;
           clonedEmployee.EmployeeDetails.EmployeeName = "Rahul New";
           clonedEmployee.EmployeeDetails.EmployeeSalary = 200;
           
           //After Changing Cloned Employee
           Console.WriteLine("After Changing in Cloned Employee:");
           Console.WriteLine("Original Employee:");
           Console.WriteLine($"Employee Id:{originalEmployee.EmployeeId}, Employee Name:{originalEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{originalEmployee.EmployeeDetails.EmployeeSalary}");
           Console.WriteLine("Cloned Employee:");
           Console.WriteLine($"Employee Id:{clonedEmployee.EmployeeId}, Employee Name:{clonedEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{clonedEmployee.EmployeeDetails.EmployeeSalary}");
           
           Console.ReadLine();
       }
   }
   
   /// <summary>
   /// Employee Class
   /// </summary>
   public class Employee
   {
       public int EmployeeId { get; set; }
       public EmployeeDetail EmployeeDetails { get; set; }
       
       /// <summary>
       /// Constructor
       /// </summary>
       /// <param name="id">id</param>
       /// <param name="salary">salary</param>
       /// <param name="name">name</param>
       public Employee(int id, int salary, string name)
       {
           EmployeeId = id;
           EmployeeDetails = new EmployeeDetail(salary, name);
       }
       
       /// <summary>
       /// Method is used to do shallow copy
       /// </summary>
       /// <returns>cloned object</returns>
       public Object ShallowCopy()
       {
           return this.MemberwiseClone();
       }
   }
   
   /// <summary>
   /// Employee Detail Class
   /// </summary>
   public class EmployeeDetail
   {
       public string EmployeeName { get; set; }
       public int EmployeeSalary { get; set; }
       
       /// <summary>
       /// Constructor
       /// </summary>
       /// <param name="salary">salary</param>
       /// <param name="name">name</param>
       public EmployeeDetail(int salary, string name)
       {
           EmployeeName = name;
           EmployeeSalary = salary;
       }
   }
}

Output

Before Changing in Cloned Employee:
Original Employee:
Employee Id:1, Employee Name:Rahul, Employee Salary:100
Cloned Employee:
Employee Id:1, Employee Name:Rahul, Employee Salary:100

After Changing in Cloned Employee:
Original Employee:
Employee Id:1, Employee Name:Rahul New, Employee Salary:200
Cloned Employee:
Employee Id:2, Employee Name:Rahul New, Employee Salary:200

Explanation

In the above example, we are doing shallow copy. 
For Employee Id, value is copied so if we change the Employee Id in cloned object, Employee Id for original object will not be changed. Here we are changing Employee Id to 2 in cloned object but Employee Id in original object remain 1.
For Employee Detail, reference is copied so if we change the Employee Name or Employee Salary in cloned object, value will also be updated for original object. Here we are changing Employee Name to Rahul New in cloned object and Employee Name is also updated to Rahul New in original object.  

 


Deep Copy

Deep copy is also used to create the cloned object by using the original object. In this type of copy, If a field is a value type, the value will be copied into the cloned object and If a field is a reference type, a new copy of the referred object is performed. So the original object and its clone will be different objects.
For doing Deep Copy, the classes must be [Serializable].

Example

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace ShallowCopyDeepCopy
{
   class Program
   {
       static void Main(string[] args)
       {
           //Original Employee
           Employee originalEmployee = new Employee(1, 100, "Rahul");
           
           //Cloned Employee
           Employee clonedEmployee = originalEmployee.DeepCopy();
           
           //Before Changing Cloned Employee
           Console.WriteLine("Before Changing in Cloned Employee:");
           Console.WriteLine("Original Employee:");
           Console.WriteLine($"Employee Id:{originalEmployee.EmployeeId}, Employee Name:{originalEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{originalEmployee.EmployeeDetails.EmployeeSalary}");
           Console.WriteLine("Cloned Employee:");
           Console.WriteLine($"Employee Id:{clonedEmployee.EmployeeId}, Employee Name:{clonedEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{clonedEmployee.EmployeeDetails.EmployeeSalary}");
           
           //Update Cloned Employee
           clonedEmployee.EmployeeId = 2;
           clonedEmployee.EmployeeDetails.EmployeeName = "Rahul New";
           clonedEmployee.EmployeeDetails.EmployeeSalary = 200;
           
           //After Changing Cloned Employee
           Console.WriteLine("After Changing in Cloned Employee:");
           Console.WriteLine("Original Employee:");
           Console.WriteLine($"Employee Id:{originalEmployee.EmployeeId}, Employee Name:{originalEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{originalEmployee.EmployeeDetails.EmployeeSalary}");
           Console.WriteLine("Cloned Employee:");
           Console.WriteLine($"Employee Id:{clonedEmployee.EmployeeId}, Employee Name:{clonedEmployee.EmployeeDetails.EmployeeName}, Employee Salary:{clonedEmployee.EmployeeDetails.EmployeeSalary}");
           
           Console.ReadLine();
       }
   }
   
   [Serializable]
   /// <summary>
   /// Employee Class
   /// </summary>
   public class Employee
   {
       public int EmployeeId { get; set; }
       public EmployeeDetail EmployeeDetails { get; set; }
       
       /// <summary>
       /// Constructor
       /// </summary>
       /// <param name="id">id</param>
       /// <param name="salary">salary</param>
       /// <param name="name">name</param>
       public Employee(int id, int salary, string name)
       {
           EmployeeId = id;
           EmployeeDetails = new EmployeeDetail(salary, name);
       }
       
       /// <summary>
       /// Method is used to do deep copy
       /// </summary>
       /// <returns>cloned object</returns>
       public Employee DeepCopy()
       {
           MemoryStream stream = new MemoryStream();
           BinaryFormatter formatter = new BinaryFormatter();
           formatter.Serialize(stream, this);
           stream.Position = 0;
           return (Employee)formatter.Deserialize(stream);
       }
   }
   
   [Serializable]
   /// <summary>
   /// Employee Detail Class
   /// </summary>
   public class EmployeeDetail
   {
       public string EmployeeName { get; set; }
       public int EmployeeSalary { get; set; }
       
       /// <summary>
       /// Constructor
       /// </summary>
       /// <param name="salary">salary</param>
       /// <param name="name">name</param>
       public EmployeeDetail(int salary, string name)
       {
           EmployeeName = name;
           EmployeeSalary = salary;
       }
   }
}

Output

Before Changing in Cloned Employee:
Original Employee:
Employee Id:1, Employee Name:Rahul, Employee Salary:100
Cloned Employee:
Employee Id:1, Employee Name:Rahul, Employee Salary:100

After Changing in Cloned Employee:
Original Employee:
Employee Id:1, Employee Name:Rahul, Employee Salary:100
Cloned Employee:
Employee Id:2, Employee Name:Rahul New, Employee Salary:200

Explanation

In the above example, we are doing deep copy. 
For Employee Id, value is copied so if we change the Employee Id in cloned object, Employee Id for original object will not be changed. Here we are changing Employee Id to 2 in cloned object but Employee Id in original object remain 1.
For Employee Detail, a new copy is created so if we change the Employee Name or Employee Salary in cloned object, value will not be updated for original object. Here we are changing Employee Name to Rahul New in cloned object and Employee Name remain same to Rahul in original object.