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);
    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: ,

Comment Section

Comments are closed.