Friday, 17 February 2017

ICloneable

ICloneable supports cloning just as its name suggests; cloning creates a new instance of the same type with the same values. Let's take a look at the definition of the ICloneable interface.

namespace System
{
    //
    // Summary:
    //     Supports cloning, which creates a new instance of a class with the same value
    //     as an existing instance.
    [ComVisible(true)]
    public interface ICloneable
    {
        //
        // Summary:
        //     Creates a new object that is a copy of the current instance.
        //
        // Returns:
        //     A new object that is a copy of this instance.
        object Clone();
    }

}

so if we implement the ICloneable interface we have to define one function that returns an object, this object could be anythings but is suppose to be a deep copy of the instance that it's being called on. Lets use our normal Person class and implement our Clone function.

class Person : ICloneable
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
    public int Age
    {
        get
        {
            var today = DateTime.Today;
            var age = today.Year - BirthDate.Year;
            return BirthDate > today.AddYears(-age) ? --age : age;
        }
    }

    public override string ToString()
    {
        return $"{Age}) {FirstName} {LastName}";
    }

    public int CompareTo(Person other)
    {
        return Age - other.Age;
    }

    public object Clone()
    {
        return new Person
        {
            FirstName = this.FirstName,
            LastName = this.LastName,
            BirthDate = this.BirthDate
        };
    }

}

Notice that we don't just return an instance of this, but we instantiate a new instance of person and set the new person's properties to that of the old one's.

class Program
{

    static void Main(string[] args)
    {
        var p1 = new Person {
            FirstName = "Pawel",
            LastName = "Ciucias",
            BirthDate = new DateTime(1984, 1, 31)
        };
        var p2 = p1.Clone() as Person;

        Console.WriteLine(p1.ToString());
        Console.WriteLine(p2.ToString());

        p1.FirstName = "Tomek";
        p1.BirthDate = new DateTime(1988, 6, 28);

        Console.WriteLine(p1.ToString());
        Console.WriteLine(p2.ToString());
    }

}

From our example we see that we duplicate our Person and then update the firstName and Birthdate, after which if we print our two people we see that they're not related, however had we created a shallow copy we'd just have to instances of Person who shared data. If we rewrote our clone function to.

public object Clone()
{
    return this;

}

we'd see that if we'd update a property in one of our instances, the other one would also change, because both Person instances share the same source.