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?
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();
}
}