Monday, 9 July 2012

Shallow copy and Deep copy using MemberwiseClone

This is basically the concept of creating the copy of an object. Sometimes you required to create a clone of an object then you can either achieve by using ICloneable interface or you can directly use MemberwiseClone() with ‘this’ keyword inside the method declaration in original class.
Shallow copy and Deep copy both are basically do similar things; copying ‘Value type’ member bit by bit. But when you have reference type in your original class then the difference between both comes into the light.
Herer is what happens with reference type when using MemberwiseClone() method-
Shallow copy copies don’t copy the reference to new memory but it create a new reference pointing to the same member object of original class. Its don’t create new memory to copy the object. See below diagram. Here 'm' is original object and 'm2' is its shallow copy.
image
Reference type created by Shallow copy is still pointing to parent(Original) member object.
Deep copy copies not only copies the value types but also provide new memory object with new reference for reference type member in the new copy class. See below diagram. Here 'm' is the same parent object and 'm3' is its deep copy.
image
Below is the code example how we can achieve Shallow Copy and Deep Copy of an object in C# using MemberwiseClone() method -
public class Job
{
    public string job = "";
    public string Department = "";
    public override string ToString()
    {
        return "My job is - " + this.job + " in department " + this.Department;
    }
}
public class MyClass
{
    public string name = "";
    public Job myjob;
    public MyClass ShallowCopy()
    {
        return (MyClass)this.MemberwiseClone();
    }
    public MyClass DeepCopy()
    {
        MyClass temp = (MyClass)this.MemberwiseClone();
        //Creating a new memory for the object and setting same values from the original
        temp.myjob = new Job { Department = this.myjob.Department, job = this.myjob.job };
        return temp;
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyClass m = new MyClass();
        m.name = "Amit";
        m.myjob = new Job { Department = "IT", job = "Developer" };
        MyClass m2 = m.ShallowCopy();
        m2.name = "Sunil";
        Console.WriteLine("m2 is taking Shallow copy of m");
        Console.WriteLine("m.value = " + m.name +" and " +m.myjob);
        Console.WriteLine("m2.value = " + m2.name + " and " + m2.myjob);
        m.myjob.Department = "Architecture";
        Console.WriteLine("m2.value = " + m2.name + " and " + m2.myjob);
        Console.WriteLine("m.value = " + m.name + " and " + m.myjob);
        Console.WriteLine("\n-----------------");
        Console.WriteLine("m3 is taking Deep copy of m");
        MyClass m3 = m.DeepCopy(); // m3 will persist the departement as Architecture
        m3.name = "Sunil";
        m.myjob.Department = "IT"; // Here we're changing the Original m's member object to IT
        Console.WriteLine("m.value = " + m.name + " and " + m.myjob);
        Console.WriteLine("m3.value = " + m3.name + " and " + m3.myjob);
        Console.WriteLine("m2.value = " + m3.name + " and " + m3.myjob);
        Console.WriteLine("m.value = " + m.name + " and " + m.myjob);
    }
}


The output of the above code would be like -

m2 is taking Shallow copy of m
m.value = Amit and My job is - Developer in department IT
m2.value = Sunil and My job is - Developer in department IT
m2.value = Sunil and My job is - Developer in department Architecture
m.value = Amit and My job is - Developer in department Architecture


-----------------
m3 is taking Deep copy of m
m.value = Amit and My job is - Developer in department IT
m3.value = Sunil and My job is - Developer in department Architecture
m2.value = Sunil and My job is - Developer in department Architecture
m.value = Amit and My job is - Developer in department IT


In the first output when changed the value of sub object in original it changed in the Shallow copied object as well. So be careful while you choose to copy the Object with MemberwiseClone();