Proper way to implement ICloneable

dotNET picture dotNET · Jan 14, 2014 · Viewed 105.8k times · Source

What is the proper way of implementing ICloneable in a class hierarchy? Say I have an abstract class DrawingObject. Another abstract class RectangularObject inherits from DrawingObject. Then there are multiple concrete classes like Shape, Text, Circle etc. that all inherit from RectangularObject. I want to implement ICloneable on DrawingObject and then carry it down the hierarchy, copying available properties at each level and calling parent's Clone at the next level.

The problem however is that since the first two classes are abstract, I cannot create their objects in the Clone() method. Thus I must duplicate the property-copying procedure in each concrete class. Or is there a better way?

Answer

Johnny5 picture Johnny5 · Jan 14, 2014

You can easily create a superficial clone with object's protected method MemberwiseClone.

Example:

   public abstract class AbstractCloneable : ICloneable
   {
      public object Clone()
      {
         return this.MemberwiseClone();
      }
   }

If you don't need anything like a deep copy, you will not have to do anything in the child classes.

The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.

If you need more intelligence in the cloning logic, you can add a virtual method to handle references :

   public abstract class AbstractCloneable : ICloneable
   {
      public object Clone()
      {
         var clone = (AbstractCloneable) this.MemberwiseClone();
         HandleCloned(clone);
         return clone;
      }

      protected virtual void HandleCloned(AbstractCloneable clone)
      {
         //Nothing particular in the base class, but maybe useful for children.
         //Not abstract so children may not implement this if they don't need to.
      }
   }


   public class ConcreteCloneable : AbstractCloneable
   {
       protected override void HandleCloned(AbstractCloneable clone)
       {
           //Get whathever magic a base class could have implemented.
           base.HandleCloned(clone);

           //Clone is of the current type.
           ConcreteCloneable obj = (ConcreteCloneable) clone;

           //Here you have a superficial copy of "this". You can do whathever 
           //specific task you need to do.
           //e.g.:
           obj.SomeReferencedProperty = this.SomeReferencedProperty.Clone();
       }
   }