Shallow copy VS Deep copy in .NET

Before doing anything let's try ti run the following example in our favorite visual studio.

     public class Person
    {
        public string Name { get; set; }
    }

    public static void Main ( )
    {
        Person [] original = new Person[1];
        original [ 0 ] = new Person ( ) { Name = "Mahbub Rahman"};
        Person [ ] clone = (Person [ ])original.Clone ( );
        clone [ 0 ].Name = "Another Name";

        Console.WriteLine ( "Original name at index 0 = {0}", original [ 0 ].Name );
        Console.WriteLine ( "Clone name at index 0 = {0}", clone [ 0 ].Name );
    }

In both cases, "Another Name" is printed though I expect in first case "Mahbub Rahman" should be printed in my sense. This is shallow copy.

Shallow copy duplicates as little as possible. If a class contains another class then shallow copy copies only the pointer, not the contents, meaning both the original instance and the duplicate instance contain the same aggregated class. With a shallow copy, two classes share the same memory location for aggregated class. So if we change the value of aggregated class in the original instance then it is reflected in the duplicated instance as well.

Deep copies duplicate everything. If a class contains a other class then deep copy creates an new instance for the aggregated class. This is shown in the following diagram. For shallow copy, the original object and the cloned object contain the same aggregated object. But for deep copy, we have separate instances of aggregated object.

    //[Serializable]
    public class ShallowDeepClass
    {
        public int Age;
        public string EmployeeName;
        public Salary EmpSalary;

        //See the MSDN documentation for MemberwiseClone()
        public ShallowDeepClass CreateShallowCopy ( ShallowDeepClass inputcls )
        {
            return (ShallowDeepClass)inputcls.MemberwiseClone ( );
        }

        public ShallowDeepClass CreateDeepCopy ( ShallowDeepClass inputcls )
        {
            ShallowDeepClass sc = new ShallowDeepClass ( );
            
            //We are creating  new instance of the Salary object and setting it to ShallowDeepClass object
            //This is difference between shallow copy and  deep copy
            Salary sal = new Salary ( inputcls.EmpSalary.mSalaryAmount );
            sc.EmpSalary = sal;
            return sc;

            //If we want to use MemoryStream instead of creating our own instance of ShallowDeepClass directly we can do that
            //We need create our class Serializable, uncomment the [Serializable] before the class declaration
            //MemoryStream m = new MemoryStream ( );
            //BinaryFormatter b = new BinaryFormatter ( );
            //b.Serialize ( m, inputcls );
            //m.Position = 0;
            //return (ShallowDeepClass)b.Deserialize ( m );
        }
    }

    //[Serializable]
    public class Salary
    {
        public Salary ( int aSalary )
        {
            mSalaryAmount = aSalary;
        }
        public int mSalaryAmount;
    }

    class program
    {
        public static void Main ( String [ ] args )
        {
            Console.WriteLine ( "Testing Shallow copy\n" );
            /// Creates an instance of ShallowDeepClass and assign values to its fields.
            ShallowDeepClass OriginalObject = new ShallowDeepClass ( );
            OriginalObject.Age = 25;
            OriginalObject.EmployeeName = "Employee Name";

            // Create an instance of Salary object  and add it to ShallowDeepClass
            Salary SalaryInstance = new Salary ( 100 );
            OriginalObject.EmpSalary = SalaryInstance;
            Console.WriteLine ( "Salary in OriginalObject before reset = {0}", OriginalObject.EmpSalary.mSalaryAmount );

            // Create a new instance of ShallowDeepClass by using CreateShallowCopy ()
            ShallowDeepClass ClonedInstance = OriginalObject.CreateShallowCopy ( OriginalObject );
            Console.WriteLine ( "Salary in ClonedInstance before reset = {0}", OriginalObject.EmpSalary.mSalaryAmount );
            // then modify the SalaryInstance salary value to be 500
            SalaryInstance.mSalaryAmount = 500;

            Console.WriteLine ( "\nSalary in OriginalObject after reset =  {0}", OriginalObject.EmpSalary.mSalaryAmount );
            Console.WriteLine ( "Salary in ClonedInstance after reset =  {0}", ClonedInstance.EmpSalary.mSalaryAmount );



            Console.WriteLine ( "\n\nTesting Deep copy\n" );


            // Performs a shallow copy of m1 and assign it to ClonedInstance.
            ShallowDeepClass DeepCopyInstance = OriginalObject.CreateDeepCopy ( OriginalObject );
            Console.WriteLine ( "Salary in OriginalObject before reset =    {0}", OriginalObject.EmpSalary.mSalaryAmount );
            Console.WriteLine ( "Salary in DeepCopyInstance before reset =  {0}", DeepCopyInstance.EmpSalary.mSalaryAmount );

            //Resetting salary
            SalaryInstance.mSalaryAmount = 800;

            Console.WriteLine ( "\nSalary in OriginalObject after reset   =  {0}", OriginalObject.EmpSalary.mSalaryAmount );
            Console.WriteLine ( "Salary in DeepCopyInstance after reset =  {0}", DeepCopyInstance.EmpSalary.mSalaryAmount );
            Console.WriteLine ( "\nNote the salary is different in both original object  and the copy object" );

            Console.ReadLine ( );
        }
    }

Output of the above code.

The above example gives idea about deep copy and shallow copy. But Microsoft provides better way for implementing cloned object, implementing ICloneable interface. Following example demonstrates the idea.

    //[Serializable]
    public class ShallowDeepClass : ICloneable
    {
        public int Age;
        public string EmployeeName;
        public Salary EmpSalary;


        //method for cloning object
        public object Clone ( )
        {
            //Clone as shallow copy uncomment  to test it
            //return this.MemberwiseClone ( );

            //Clone as deep copy, comment it to test only MemberwiseClone()
            ShallowDeepClass sc = (ShallowDeepClass)this.MemberwiseClone ( );
            Salary sal = new Salary ( this.EmpSalary.mSalaryAmount );
            sc.EmpSalary = sal;
            return sc;
        }
    }

    //[Serializable]
    public class Salary
    {
        public Salary ( int aSalary )
        {
            mSalaryAmount = aSalary;
        }
        public int mSalaryAmount;
    }

    class program
    {
        public static void Main ( String [ ] args )
        {

            Console.WriteLine ( "Testing Shallow copy via simple assignment\n" );
            /// Creates an instance of ShallowDeepClass and assign values to its fields.
            ShallowDeepClass OriginalObject = new ShallowDeepClass ( );
            OriginalObject.Age = 25;
            OriginalObject.EmployeeName = "Employee Name";

            // Create an instance of Salary object  and add it to ShallowDeepClass
            Salary SalaryInstance = new Salary ( 100 );
            OriginalObject.EmpSalary = SalaryInstance;
            Console.WriteLine ( "Salary in OriginalObject before reset = {0}", OriginalObject.EmpSalary.mSalaryAmount );

            // Create a new instance of ShallowDeepClass by using the assignment
            ShallowDeepClass AssignedInstance = OriginalObject;
            Console.WriteLine ( "Salary in AssignedInstance before reset = {0}", AssignedInstance.EmpSalary.mSalaryAmount );
            // then modify the SalaryInstance salary value to be 500
            SalaryInstance.mSalaryAmount = 500;

            Console.WriteLine ( "\nSalary in OriginalObject after reset =  {0}", OriginalObject.EmpSalary.mSalaryAmount );
            Console.WriteLine ( "Salary in AssignedInstance after reset =  {0}", AssignedInstance.EmpSalary.mSalaryAmount );


            Console.WriteLine ( "\n\nTesting Shallow copy via ICloneable interface\n" );

            // Create a new instance of ShallowDeepClass by using the interface
            ShallowDeepClass ClonedInstance = (ShallowDeepClass)OriginalObject.Clone ( );
            Console.WriteLine ( "Salary in AssignedInstance before reset = {0}", AssignedInstance.EmpSalary.mSalaryAmount );
            // then modify the SalaryInstance salary value to be 500
            SalaryInstance.mSalaryAmount = 700;

            Console.WriteLine ( "\nSalary in OriginalObject after reset =  {0}", OriginalObject.EmpSalary.mSalaryAmount );
            Console.WriteLine ( "Salary in ClonedInstance after reset =  {0}", ClonedInstance.EmpSalary.mSalaryAmount );

            Console.ReadLine ( );
        }
    }

This site is updated and maintained by Mahbub Rahman.
Updated on 06/21/2015
if you want to contribute or comment please contact me.