http://www.codinghelmet.com/  

Wear a helmet. Even when coding.

howto > icloneable

How to Implement ICloneable Interface in Derivable Classes in .NET
by Zoran Horvat @zoranh75

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.

This article gives guidelines that should be followed when developing base class which implements ICloneable interface.

As will be explained and demonstrated, all implementations should stick to these guidelines:

  • Base class (which implements System.ICloneable interface) should contain public or protected copy constructor.
  • Base class should declare Clone method as virtual.
  • Derived class should contain copy constructor which calls base class's copy constructor.
  • Both base and derived class should implement Clone method by simply invoking the copy constructor.

These guidelines will be explained in more details in following sections.

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?.

Example Cloneable Class

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.

class PriceTag
{

    public PriceTag()
    {
        _pounds = _rnd.Next(10, 100);
    }

    public int Pounds
    {
        get { return _pounds; }
    }

    public override string ToString()
    {
        return string.Format("{0} GBP", _pounds);
    }

    private int _pounds;
    protected static Random _rnd = new Random();

}

This little class initializes random price between 10 and 99 pounds (inclusive) so that any instance will differ from 89 out of 90 other instances, unless cloned. And here this class is in action:

static void Main(string[] args)
{

    PriceTag pt = new PriceTag();
    Console.WriteLine(pt);

}

Output depends on seed taken when random number generator was initialized, and may look like this:

82 GBP

Now let's suppose that we want to make this class cloneable. As simple as it can be, we will just implement System.ICloneable interface so that Clone() method copies contained price into new object:

class PriceTag: ICloneable
{
    ...
    public object Clone()
    {
        PriceTag pt = new PriceTag();
        pt._pounds = _pounds;
        return pt;
    }
    ...
}

And these are changes made to Main function to test the Clone() method:

PriceTag pt = new PriceTag();
PriceTag clone = pt.Clone() as PriceTag;

Console.WriteLine(pt);
Console.WriteLine(clone);

Output shows that cloning went fine:

46 GBP
46 GBP

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.

Adding Derived Class

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:

class PencePriceTag: PriceTag
{

    public PencePriceTag()
    {
        _pence = PriceTag._rnd.Next(20) * 5;
    }

    public override string ToString()
    {
        return string.Format("{0}.{1} GBP", Pounds, _pence);
    }

    private int _pence;

}

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:

PencePriceTag ppt = new PencePriceTag();
object clone = ppt.Clone();

Console.WriteLine(ppt);
Console.WriteLine(clone);

Test code prints the output:

38.40 GBP
38 GBP

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:

class Program
{
    static void CloneAndPrint(ICloneable obj)
    {
        Console.WriteLine(obj);
        Console.WriteLine(obj.Clone());
    }

    static void Main(string[] args)
    {
        CloneAndPrint(new PencePriceTag());
    }
}

This code compiles well but works bad, which is a bug by definition.

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.

Adding Cloneability to Derived Class

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.

First step is to make the Clone() method virtual. That will allow derived classes to re-implement it as they will:

class PriceTag: ICloneable
{

    ...
    public virtual object Clone()
    {
        PriceTag pt = new PriceTag();
        pt._pounds = _pounds;
        return pt;
    }
    ...

}

Now it remains that derived class override the Clone() method and add its own cloning operations. Naive approach might look something like this:

class PencePriceTag: PriceTag
{

    ...
    public override object Clone()
    {
        PencePriceTag ppt = new PencePriceTag();
        ppt._pence = this._pence;
        return ppt;
    }
    ...

}

Values printed by this code point out the mistake:

54.55 GBP
75.55 GBP

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:

class PriceTag: ICloneable
{

    ...
    public PriceTag(PriceTag pt)
    {
        _pounds = pt._pounds;
    }
    ...
    public virtual object Clone()
    {
        return new PriceTag(this);
    }
    ...

}

class PencePriceTag: PriceTag
{

    ...
    public PencePriceTag(PencePriceTag ppt): base(ppt)
    {
        _pence = ppt._pence;
    }
    ...
    public override object Clone()
    {
        return new PencePriceTag(this);
    }
    ...

}

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:

84.20 GBP
84.20 GBP

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.

Conclusion

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:

  • Implement non-private copy constructor in derived class; this constructor will be used from derived class constructor to initialize members controlled by the base class, as well as from inside Clone() method to create deep copy of current instance.
  • Declare Clone() method virtual so that derived class can modify it; this also ensures correctness of polymorphic calls.
  • Implement non-private copy constructor in derived class; call base class's copy constructor to initialize base class members.
  • Override Clone() method in derived class and implement cloning facility for derived class in that method.

Disobeying these rules means that derived class will not be able to override inherited cloning ability and hence Clone() method invoked on derived class would return incorrect result.

For more information about the ICloneable interface please refer to article The ICloneable Controversy: Should a Class Implement ICloneable Or Not?.

See also:

Published: Sep 19, 2011; Modified: Apr 30, 2013

ZORAN HORVAT

Zoran is software architect dedicated to clean design and CTO in a growing software company. Since 2014 Zoran is an author at Pluralsight where he is preparing a series of courses on design patterns, writing unit and integration tests and applying methods to improve code design and long-term maintainability.

Follow him on Twitter @zoranh75 to receive updates and links to new articles.

Watch Zoran's video courses at pluralsight.com (requires registration):

Tactical Design Patterns in .NET: Managing Responsibilities

Applying a design pattern to a real-world problem is not as straightforward as literature implicitly tells us. It is a more engaged process. This course gives an insight into tactical decisions we need to make when applying design patterns that have to do with separating and implementing class responsibilities. More...

Tactical Design Patterns in .NET: Control Flow

Improve your skills in writing simpler and safer code by applying coding practices and design patterns that are affecting control flow. More...

Improving Testability Through Design

This course tackles the issues of designing a complex application so that it can be covered with high quality tests. More...

Share this article

webmasters