.NET

Assume we have a class that implements the C# interface ICloneable. It has one method called Clone(), which is supposed to return a new instance of the object with its instance members copied. Assume we later create a subclass that has additional properties. If we want our subclass to be properly cloned, we need to implement Clone in it too. However, how do we avoid copying the logic from the parent’s Clone method and keeping it DRY?

Let’s start with the following simple program. It has a parent class Vehicle, and a child class Car. The problem with the Car class is that it copies MaxVelocity in the same way as its parent. If we later add new properties to Vehicle, we would also need to remember to update the Clone METHOD OF ALL sub-classes, which is a problem.

using System;

public class Vehicle : ICloneable
{
    public double MaxVelocity { get; set; } = 0.0;

    public object Clone()
    {
        var vehicle = new Vehicle();
        vehicle.MaxVelocity = MaxVelocity;
        return vehicle;
    }
}

public class Car : Vehicle
{
    public int NumberOfWheels { get; set; } = 0;

    public new object Clone()
    {
        var car = new Car();
        car.MaxVelocity = MaxVelocity;
        car.NumberOfWheels = NumberOfWheels;
        return car;
    }
}
 
public class Test
{
    static void Main ()
    {
        var car = new Car{
            MaxVelocity = 12.25,
            NumberOfWheels = 4,
        };
        Console.WriteLine("Car: {0} {1}", car.MaxVelocity, car.NumberOfWheels);
        var copy = (Car) car.Clone();
        Console.WriteLine("Car: {0} {1}", copy.MaxVelocity, copy.NumberOfWheels);
    }
}

The solution is to introduce a copy constructor to Vehicle that instantiates itself with the values from a given Vehicle instance. We will do the same to the Car class, with the crucial difference that it also passes the given Car instance to its parent that copies everything shared between Vehicles. With these additions, we can also refactor the Clone methods and make them simpler.

The updated versions of Vehicle and Car can be seen below. The class Test hasn’t been modified and is therefore not shown.

public class Vehicle : ICloneable
{
    public double MaxVelocity { get; set; } = 0.0;

    public Vehicle() {}

    public Vehicle(Vehicle vehicle)
    {
        MaxVelocity = vehicle.MaxVelocity;
    }

    public object Clone()
    {
        return new Vehicle(this);
    }
}

public class Car : Vehicle
{
    public int NumberOfWheels { get; set; } = 0;

    public Car() {}

    public Car(Car car) : base(car)
    {
        NumberOfWheels = car.NumberOfWheels;
    }

    public new object Clone()
    {
        return new Car(this);
    }
}

As we can see, this change results in very clean, maintainable and DRY code.