The ICloneable interface enables you to provide a customized implementation that creates a copy of an existing object. The ICloneable interface contains one member, the Clone method, which is intended to provide cloning support beyond that supplied by Object.MemberwiseClone. For more information about cloning, deep versus shallow copies, and examples, see the Object.MemberwiseClone method.
The ICloneable interface simply requires that your implementation of the Clone() method return a copy of the current object instance. It does not specify whether the cloning operation performs a deep copy, a shallow copy, or something in between. Nor does it require all property values of the original instance to be copied to the new instance. For example, the Clone() method performs a shallow copy of all properties except the IsReadOnly property; it always sets this property value to false in the cloned object. Because callers of Clone() cannot depend on the method performing a predictable cloning operation, we recommend that ICloneable not be implemented in public APIs.
It is common requirement in .NET programming to create a cloneable class, i.e. to implement System.ICloneable interface. Another common requirement is to implement a class which would serve as a base class to other classes. It is somewhat less common to implement both requirements at the same class, i.e. to make a class cloneable in such way that classes derived from it are also cloneable.
For guidelines on making decision whether a class should implement ICloneable interface in the first place, please refer to article The ICloneable Controversy: Should a Class Implement ICloneable Or Not?.
As a matter of demonstration, we will create one base class and one derived class. Base class will be called PriceTag, and it will contain randomly generated price (in pounds), rounded to one pound. Its ToString() method will show a correctly formatted price tag.
Again, output varies in each execution due to random nature of the class, but both lines show the same price tag as required. If run many times, this code will always produce and print out two exactly the same objects, proving that ICloneable interface is properly implemented.
Now suppose that we want to add pennies to our price tags. That would require deriving a class, named PencePriceTag, which will add new functionality. It will randomly generate pennies at 5p precision so to ensure that any two instances of this class would mostly often show different price. Here is the class:
Now note that PencePriceTag class has the inherited Clone() method. However, this does not mean that cloning has been implemented in the derived class, because base class's implementation of Clone() method only returns new instance of the base class, as shown in the following test:
This piece of code has created an instance of derived class and then attempted to clone it. Note that Clone() method returns System.Object, and casting it to PencePriceTag will fail because in this case return value would be of type PriceTag. As expected, this code has printed out different objects, showing that cloning has actually failed.
The problem here is not only that derived class does not clone correctly (it does not clone at all), but also that derived class most obviously implies that it is cloneable - it implements ICloneable interface and has the Clone() method. So any user of this code will be invited to clone objects of the derived class PencePriceTag, but then the code will not work! For example, take a method which receives ICloneable objects:
From this demonstration it is obvious that explicit cloning facility must be implemented in every class which is derived from class implementing ICloneable interface. However, there is a fact that base class potentially contains some fields or data structures that are inaccessible to derived class. This may significantly complicate the situation.
Up to this point we have outlined the problem. Once class implementing ICloneable is derived, it automatically results in a fake cloneable class, i.e. a class which implements ICloneable interface but does not clone when asked to. Even more, derived class has no way to change that! The Clone() method is implemented in base class and that cannot be affected by the derived class. (All this time we are assuming worst case, i.e. that we are unable to modify base class.)
To solve the problem in a regular object-oriented manner, author of the base class must be aware that class will be extended by derived classes, and hence must be aware of the possible problems that will be caused by the Clone() method. Hence, two steps must be done, of which first one is cosmetics and the second one is fundamental.
Pennies have been copied right, but pounds were not copied at all (but rather generated randomly again). This is because only derived implementation of the Clone() method has been executed. Members of the base class have been initialized by the base class's default constructor, instead of copied from the instance being cloned.
Consequently, we come to the fundamental step which would rectify the problem, and that is to add a facility to the base class which will allow derived class to copy base members into the cloned object. Most natural way to do so is to implement copy constructor in the base class (this is generally advisable to do whether class being cloneable or not). Copy constructor would be in charge of performing the deep copy of one instance into newly created instance.
Similarly, derived class would have own copy constructor, which effectively performs the cloning. Clone method in both classes would now just create new instance of the same class using its copy constructor. Here is the implementation:
Observe that the derived class is coded with exactly the same guidelines as the base class - Clone() method remains virtual and there is a copy constructor implemented. This is because we cannot say that someone is not going to derive yet another class from this one (e.g. the one that implements multiple currencies). That class would certainly like to be able to clone itself correctly once things come to that point.
Now we can safely invoke previously introduced CloneAndPrint() method, which is now going to create full deep copy of the derived class, including base class members. Sample output may look like this:
Keep on mind that copy constructor technique ensures that base class members will be deep-copied before derived class members, which is extremely important. Initialization of derived class members may depend on base class members and order of initializations must be strictly obeyed.
Whenever a class implements System.ICloneable interface it implements Clone() method which performs a deep copy operation on objects of that class. However, derived classes may be left in state in which they do contain inherited Clone() method, but cannot implement it correctly. In order to avoid this unfortunate situation, base class must either forbid deriving (by using sealed C# keyword, or NotInheritable in VisualBasic.NET), or explicitly support cloneability in derived classes. This is done in these steps:
In this course, you will learn the basic principles of object-oriented programming, and then learn how to apply those principles to construct an operational and correct code using the C# programming language and .NET.
As the course progresses, you will learn such programming concepts as objects, method resolution, polymorphism, object composition, class inheritance, object substitution, etc., but also the basic principles of object-oriented design and even project management, such as abstraction, dependency injection, open-closed principle, tell don't ask principle, the principles of agile software development and many more.
This course begins with examination of a realistic application, which is poorly factored and doesn't incorporate design patterns. It is nearly impossible to maintain and develop this application further, due to its poor structure and design.
As demonstration after demonstration will unfold, we will refactor this entire application, fitting many design patterns into place almost without effort. By the end of the course, you will know how code refactoring and design patterns can operate together, and help each other create great design.
After completing this course, you will know how to develop a large and complex domain model, which you will be able to maintain and extend further. And, not to forget, the model you develop in this way will be correct and free of bugs.
Zoran Horvat is the Principal Consultant at Coding Helmet, speaker and author of 100+ articles, and independent trainer on .NET technology stack. He can often be found speaking at conferences and user groups, promoting object-oriented and functional development style and clean coding practices and techniques that improve longevity of complex business applications.
Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.
Clone() in C# is a string method used to return the exact copy of an object. It returns the instance of the string. The return is just a copy with a different view. This method is also useful if we want to clone an array. In the case of the array, it creates a copy of the array with the same number of elements. The Clone method in the ICloneable interface allows for the copying of data. You do not need to provide any parameters for this method.
Using the clone () method makes it easy for the developers as they need to write less code that is easy to understand. No other special attribute is required along with this; it copies all properties. We can call this method inside the class only. It returns an object, so we need to do casting when we use this method. It is good to implement this method in all classes to clone. We can achieve it by using two techniques 1. Deep copy 2. Shallow copy.
c80f0f1006