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.
Comments are closed.