Object Cloning
At times, you want to take an existing object and make a copy of it. For example, you might want to make a copy of an Int32, a String, an ArrayList, a Delegate, or some other object. For some types, however, cloning an object instance doesn't make sense. For example, it doesn't make sense to clone a System.Threading.Thread object because creating another Thread object and copying its fields doesn't create a new thread. Also, for some types, when an instance is constructed, the object is added to a linked list or some other data structure. Simple object cloning would corrupt the semantics of the type.
A class must decide whether or not it allows instances of itself to be cloned. If a class wants instances of itself to be cloneable, the class should implement the ICloneable interface, which is defined as follows:
public interface ICloneable { Object Clone(); }
This interface defines just one method, Clone. Your implementation of Clone is supposed to construct a new instance of the type and initialize the new object's state so that it is identical to the original object. The ICloneable interface doesn't explicitly state whether Clone should make a shallow copy of its fields or a deep copy. So, you must decide for yourself what makes the most sense for your type and then clearly document what your Clone implementation does.
NOTE
For those of you who are unfamiliar with the term, a shallow copy is one in which the values in an object's fields are copied but what the fields refer to is not copied. For example, if an object has a field that refers to a string and you make a shallow copy of the object, then you have two objects that refer to the same string. On the other hand, in a deep copy, you make a copy of what an object's fields refer to. So, if you made a deep copy of an object that has a field that refers to a string, you'd be creating a new object and a new stringthe new object would refer to the new string. The important thing to note about a deep copy is that the original and the new object share nothing; modifying one object has no effect on the other object.
Many developers implement Clone so that it makes a shallow copy. If you want a shallow copy made for your type, implement your type's Clone method by calling System.Object's protected MemberwiseClone method, as demonstrated here:
class MyType : ICloneable { public Object Clone() { return MemberwiseClone(); } }
Internally, Object's MemberwiseClone method allocates memory for a new object. The new object's type matches the type of the object referred to by the this reference. MemberwiseClone then iterates through all the instance fields for the type (and its base types) and copies the bits from the original object to the new object. Note that no constructor is called for the new objectits state will simply match that of the original object.
Alternatively, you can implement the Clone method entirely yourself, and you don't have to call Object's MemberwiseClone method. Here's an example:
class MyType : ICloneable { ArrayList set; // Private constructor called by Clone private MyType(ArrayList set) { // Refer to a deep copy of the set passed. this.set = set.Clone(); } public Object Clone() { // Construct a new MyType object, passing it the // set used by the original object. return new MyType(set); } }
You might have realized that the discussion in this section has been geared toward reference types. I concentrated on reference types because instances of value types always support making shallow copies of themselves. After all, the system has to be able to copy a value type's bytes when boxing it. The following code demonstrates the cloning of value types:
static void Main() { Int32 x = 5; Int32 y = x; // Copy the bytes from x to y. Object o = x; // Boxing x copies the bytes from x to the heap. y = (Int32) o; // Unbox o, and copy bytes from the heap to y. }
Of course, if you're defining a value type and you'd like your type to support deep cloning, then you should have the value type implement the ICloneable interface as shown earlier. (Don't call MemberwiseClone, but rather, allocate a new object and implement your deep copy semantics.)