Introduction
In this article, I shall talk about an interesting aspect of .NET programming - Cloning objects. This article talks about why cloning of objects is required, how it can be done and some considerations of cloning.
Background
You all must be aware that .NET objects are of two types: Value and Reference types. Variables of value type objects hold the object bits itself and have "copy-on-assignment" behavior. That said, the rest of this discussion does not apply to value types.
On the other hand, variables of Ref types are actually pointers to some memory on the heap. Therefore, if you create a new variable of a ref type and assign it to an existing object, you are actually creating another pointer to the same memory on the heap. So, what do you do if you need to create a new copy of an object and hold it in a variable - this article is written for just that!
So, Why Clone?
I would say cloning is really required if setting up the state of an object is expensive and you just need a copy of the object to do some changes to the existing state. Let's take a good example to understand what I have just said. Consider the DataTable
class. Building a DataTable
can involve operations like querying the database for the schema and data, adding constraints, setting the primary key and so on. So, if you want a new copy of this DataTable
, just for making minor changes to the schema or adding a new row etc, it would be more wise just to clone an existing object and work on that, rather than recreating a new DataTable
, which can require more time and resources.
Cloning is also widely applicable to Array
s and Collections, where you need a copy of existing elements many a time.
Types of Cloning
We can classify two types of cloning based on "how much" is cloned: Deep and Shallow. A shallow clone is a new instance of the same type as the original object, which contains a copy of the value typed fields. But, if the field is a reference type, the reference is copied, not the referred object. Hence, the reference in the original object and the reference in the clone point to the same object. A deep clone of an object, on the other hand, contains a copy of everything directly or indirectly referenced by the object. Let's take up an example.
X is an object with references to the object A and the object A also has a reference to an object M. A shallow copy of X is an object Y, which also has references to object A. In contrast, a deep copy of X is an object Y with direct reference to object B, and an indirect reference to object N, where B is a copy of A, and N is a copy of M. This is visually depicted below to understand this better.
Implementing Cloning
System.Object
provides a protected method MemberwiseClone
which can be used to implement Shallow cloning. This method is marked as protected, so you can access this method in context of a derived class or within that class itself.
.NET defines an interface called IClonable
which has to be implemented by classes that need functionality beyond the scope of shallow cloning (for deep cloning). We need to provide a suitable implementation in the Clone
method of the interface to do the same.
There are various ways to implement deep cloning. One method is to serialize the object into a memory stream and deserialize it back into a new object. We would need to use a Binary formatter or SOAP formatter which do a deep serialization. The problem with this approach is that the class and its members (the entire object graph) have to be marked as serializable, else the formatter would through an exception.
Reflection may be another method to achieve the same. One good article written by Amir Harel caught my eye. He provides a good clone implementation using this method. The discussion on the article is good too! Here's the link
Understand that, for either of the methods discussed above, the member types must support cloning themselves for deep cloning to be successful. That is, the object graph must be serializable or the individual member must provide an implementation of IClonable. If this is not the case, then we would not be able to deep clone the object at all!
Conclusion
Cloning is a nifty thing to provide as a programmer. But, one should be aware of the need to provide the same and under some circumstances, objects should strictly not should provide this feature. Take for example the SQLTransaction
class, which does not support cloning. This class represents a transaction in a SQL Server database. Cloning the object would not make sense, since we possibly cannot comprehend a clone of an active transaction in a database! Therefore, if you think the cloning the state of an object can create inconsistencies in the logic of an application, dont support cloning.
In this article, I have put down everything I have understood about cloning an object in .NET. If you have any other ideas, opinions or contradictions, please feel free to discuss the same. This should help me foster a better understanding!