Tuesday, September 4, 2007

C# Copy Semantics

Let 's talk about Copy Semantics a little bit in C# Tuning
There is three type of object copy in C#.

  1. Reference copy
  2. Shallow copy
  3. Deep copy
As you may now the default behavior of c# compiler is the first one. Let me explain it by a sample:

Person p = new Person("Ali", 40);

Person p2 = p;
p2.Name = "Reza";
Console.WriteLine(p.Name); // ==>> the result is Reza
Console.WriteLine (p2.Name); // ==>> the result is Reza

By default when you have the code above you will get a reference copy of your p object. It means that, if you change the value of p2 it will effect the values of p.
So if I want a real copy of my object what I have to do?
There is two way to do this, but with a different. Imagine that I have a class named Invoice which has a reference to Person class, like this:

public class Invoice
{
public int No;
public DateTime Date;
public Person Customer;
//.............
}

Now I want to have a copy of my Invoice object inc.

Invoice inc = new Invoice("1001",DateTime.Now,new Person("Reza",40));

// Invoice inc2 = inc; // It 's not what I really want.

So I have to use the second type of object copy which is Shallow copy. In Shallow Copy you will get a new object with all the values copies to the new object. But the point is that you just have a reference copy of you related references types (like Customer: Person). To get a Shallow Copy of your object you can use MemberwiseClone() method of object. I've created a method called ShallowCopy() in my Invoice class.

public Invoice ShallowCopy()
{
return (Invoice)this.MemberwiseClone();
}

Then if you create an object copy of your invoice and change No or Date values this will not effect to the inc object values. But changing the value of it 's Customer, will do:

Invoice inc2 = inc.ShallowCopy();
inc2.No = 1002;
inc2.Customer.Name = "Masoud";
Console.WriteLine("Invoice No: {0}, Customer Name :{1}",inc.No,inc.Customer.Name); // ==>
I nvoice No: 1001, Customer Name : Masoud
Console.WriteLine("Invoice No: {0}, Customer Name :{1}",inc2.No,inc2.Customer.Name);// ==> Invoice No: 1002, Customer Name : Masoud

To get a Deep Copy of you object, you have to implement IClonable interface for Invoice and all of it 's related classes:

public class Invoice: IClonable
{
public int No;
public DateTime Date;
public Person Customer;
//.............

public object Clone()
{
Invoice myInvoice = (Invoice)this.MemberwiseClone();
myInvoice.Customer = (Person) this.Customer.Clone();
return myInvoice;
}
}

public class Person: IClonable
{
public string Name;
public int Age;

public object Clone()
{
return this.MemberwiseClone();
}
}

Now you have a real deep copy of you invoice object.

Invoice inc3 = (Invoice) inc.Clone();
inc3.No = 1003;
inc3.Customer.Name = "Mohammad";
Console.WriteLine("Invoice No: {0}, Customer Name :{1}",inc.No,inc.Customer.Name); // ==>
I nvoice No: 1001, Customer Name : Masoud
Console.WriteLine("Invoice No: {0}, Customer Name :{1}",inc2.No,inc2.Customer.Name);// ==> Invoice No: 1002, Customer Name : Masoud
Console.WriteLine("Invoice No: {0}, Customer Name :{1}",inc3.No,inc3.Customer.Name);// ==> Invoice No: 1003, Customer Name : Mohammad

You can download the sample code at:
http://www.tabatabaei.info/csharpsamples/copysemantics.rar

10 comments:

Marcus said...

Thanks, that really clarified some behaviour for a developer lurking into C# from a C++ point of view =)

G said...

probably the best example of copying I've come across in c#

thanks.

Anonymous said...

Thanks for the excellent example, now it is clear

DieDaily said...

So clear and concise...now why can't the help files be like that!!

Nefarious said...

Thank you soo much! This really cleared up an issue I was having! =)

Anonymous said...

don`t see the use, why not ceate a new instance of the object? You are doing this with the copy so what is the difference?

Say I want to make multiple instance of a class, but don`t know at runtime how many, how can I do this?. Say based on a fieldcount from db?

omerseyrek said...

thanks soo much. This issue is very simple and helpfull for me. Just the information that i need.

Frank said...

Thank you so much for being clear and easy to understand! Your articles are extremely well organized. Once again, thank you !

Peter said...

Thanks a lot! It was a lot of help.

Anonymous said...

Concise and precise! Great explanation. Thanks