Introduction
When we copy one instance to another using C# what happen is that both instances share the same memory address. But this is not the behavior we want most of the time.
When we create a copy of an object, for example:
MyClass obj=new MyClass()
MyClass obj2=obj;
Then the '=' operator copies the reference and not the object (and it works fine for a Value Type).
By default we get this behavior using the MemberwiseClone() method that is defined in the super class called System.Object. This is called “Shallow Copy”.
To get the same behavior for a Reference Type as well as a Value Type we use the Clone() method that belongs to the System.ICloneable interface. This is called a “Deep Copy”.
We will see both behaviors in depth one by one.
Shallow Copy
A Shallow Copy is about copying an object's value type fields into the target object and the object's reference types are copied as references into the target object but not the referenced object itself. It copies the types bit by bit. The result is that both instances are cloned and the original will refer to the same object.
We can get this behavior using MemberwiseClone() as mentioned earlier.
Now let's demonstrate this behavior using the following code:
class ShallowCopy
{
public int I {get;set;}
public int J {get;set;}
}
class Demo
{
public static void Main()
{
ShallowCopy obj=new ShallowCopy();
ShallowCopy objClone=obj;
obj.I=10;// setting obj value after cloning..
Console.WriteLine(“objvalue : {0} \t Clone value : {1}”,obj.I,objClone.I=10);
}
Output : obj value : 10 Clone value : 10
Surprise! This is not what we were looking for, right? So here the MemberwiseClone() method is useful. Let's change the class as in the following:
class ShallowCopy : ICloneable
{
public int I {get;set;}
public int J {get;set;}
//method for cloning object
public object Clone()
{
return this.MemberwiseClone();
}
}
class Demo
{
public static void Main()
{
ShallowCopy obj=new ShallowCopy();
Console.WriteLine(“--------before Shellow Clopy------”);
ShallowCopy objClone=obj;
obj.I=10;// setting obj value after cloning..
Console.WriteLine(“objvalue : {0} \t Clone value : {1}”,obj.I,objClone.I=10);
Console.WriteLine(“--------after Shellow Copy------”);
ShallowCopy objClone2=(ShallowCopy)obj.Clone(); // cast object to //ShallowCopy
obj.I=1000; // MemberwiseClone() will not use this reference..
Console.WriteLine(“after using MemberwiseClone() Clone() method :{0}”,objClone2.I);
}
}
Output:
--------before Shellow Clopy------
obj value :10 Clone value :10
--------after Shellow Copy------
after using MemberwiseClone() Clone() method :10
Now it works as expected.
As per the above example the Clone() method is creating a true copy of an object and creating a new heap in memory for a cloned instance.
But what if we use a Refrence Type instead of primitive data types?
The answer is, for Reference Types, MeberwiseClone() does not clone an object.
In other words, if we use any reference type in the ShallowCopy class, for example:
Class ShallowCopy
{
...public String K {get;set;}
}
This behavior is like we are copying files and folders from one directory to another, but it's copying files and folders only, not the files that are there inside the folder.
Now to make this Clone() method for a complete copy (deep copy) let's explore the concept of Deep Copy.
Deep Copy
Deep Copy is used to make a complete deep copy of the internal reference types, for this we need to configure the object returned by MemberwiseClone().
In another words a deep copy occurs when an object is copied along with the objects to which it refers.
Let's understand it using the following code:
class ReferenceType
{
public int RFT { get; set; }
}
class ShallowCopy : ICloneable
{
public int I { get; set; }
public int J { get; set; }
public ReferenceType K = new ReferenceType();
//Method updated for reference type ..
public object Clone()
{
// Shalllow Copy..
ShallowCopy SC = (ShallowCopy)this.MemberwiseClone();
// Deep copy...
ReferenceType RT = new ReferenceType();
RT.RFT = this.K.RFT;
SC.K = RT;
return SC;
}
public static void Main(String[] args)
{
ShallowCopy obj = new ShallowCopy();
obj.K.RFT = 100;
ShallowCopy objclone = (ShallowCopy)obj.Clone();
obj.K.RFT = 200; // make changes in obj.
Console.WriteLine(objclone.K.RFT);
}
}
Output : 100.
The code that is marked as bold shows how to configure a Deep Copy for a Reference Type to get the behavior we want.
Now in this case the clone object refers to a completely different copy along with a reference type.
Here is a simple image that describe both: