This topic has been done to death but I see the occasional errors in code that are directly related to a misunderstanding of “shallow” vs “deep” copies of reference types. Putting it here provides an outlet for my thoughts and a link I can point developers to so I do not have to repeat myself.

A shallow copy is best illustrated by the following diagram. Effectively both variables A and B are pointing at the same memory address, so any updates to A are reflected in B and vice versa:

Here is some code that performs a shallow copy:

MyClass c1 = new MyClass();
MyClass c2 = c1; // A shallow copy is performed here

c1.SC.SomeValue = "25";
c1.ST = "45";

//c2 will reflect the changes made to c1 above, trust me.
MessageBox.Show(String.Format("SomeValue: {0} : ST: {1}",c2.SC.SomeValue,c2.ST));

In C# shallow copies can explicitly performed by a MemberWiseClone and can be completed as follows:

MyClass c2 = c1.MemberWiseClone();

In contrast a deep copy creates and entirely new memory space from which the variables are referenced as show:

In order to provide deep copy capabilities you can use the ICloneable interface and make your class Serializable (I am sure there are other ways to do this).

public object Clone()
{
    MemoryStream ms = new MemoryStream();
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(ms, this);
    ms.Position = 0;
    object o = bf.Deserialize(ms);
    ms.Close();
    return o;
}

So now the code for completing a deep copy would look something like this…

MyClass c1 = new MyClass();
MyClass c2 = (MyClass)c1.Clone();

c1.SC.SomeValue = "25";
c1.ST = "45";

//the message below will have empty strings as c2 was never initialized.
MessageBox.Show(String.Format("SomeValue: {0} : ST: {1}",c2.SC.SomeValue,c2.ST));

Please do not make the assumption that all ICloneable implementations are deep, Framework design guidelines were very vague and developers are notoriously inconsistent. You have been warned.

Technorati Tags: ,