Creating Cloneable Objects in C# using ICloneable

In C#, any object whether it is predefined object or user defined object is of reference type. So if we assign one object to another object it just assigns the reference to the same object in memory. After assigning also if you change the value of one of the object member automatically second object member value will get change. For example, we have Employee class with Id and Name properties as shown below.

Open Microsoft Visual Studio 2015 => Create Console Application and name it as CSharpCloneableObject. Add Employee class as shown below.

using System; 

namespace CSharpCloneableObject

{

    public class Employee

    {

        public int id;

        public string name; 

        public Employee(int id, string name) { this.id = id; this.name = name; }

    }

} 

Let’s create object obj1 for Employee class and give some values to Id, Name properties. Assign this object to new Employee object obj2 as shown below.

using System; 

namespace CSharpCloneableObject

{

    class Program

    {

        static void Main(string[] args)

        {

            Employee obj1 = new Employee(100, "Raj");             

            Employee obj2 = obj1;            

            Console.WriteLine("Before obj2 change, obj1 Values Id:{0}; Name:{1}:", obj1.id, obj1.name);

            Console.WriteLine("Before obj2 change, obj2 Values Id:{0}; Name:{1}:", obj2.id,obj2.name); 

            obj2.id = 101;

            obj2.name = "David"; 

            Console.WriteLine("After obj2 change, obj1 Values Id:{0}; Name:{1}:", obj1.id, obj1.name);

            Console.WriteLine("After obj2 change, obj2 Values Id:{0}; Name:{1}:", obj2.id, obj2.name);

            Console.ReadLine();

        }

    }

}

 

As shown above, we have changed the second object obj2 values, this changes the obj1 values also. The above program gives the output as below.

As shown, by changing the obj2 values obj1 values also getting changed because we just assign the obj1 reference to obj2. But our aim is to create the existing object which does not depend on each other. We can create clone the object by implementing the ICloneable interface Clone() method as shown below.

using System; 

namespace CSharpCloneableObject

{

    public class Employee : ICloneable

    {

        public int id;

        public string name;

        public Employee(int id, string name) { this.id = id; this.name = name; } 

        public object Clone()

        {

            return new Employee(this.id, this.name);

        }

    }

}

 

using System; 

namespace CSharpCloneableObject

{

    class Program

    {

        static void Main(string[] args)

        {

            Employee obj1 = new Employee(100, "Raj");             

            Employee obj2 = (Employee) obj1.Clone();            

            Console.WriteLine("Before obj2 change, obj1 Values Id:{0}; Name:{1}:", obj1.id, obj1.name);

            Console.WriteLine("Before obj2 change, obj2 Values Id:{0}; Name:{1}:", obj2.id,obj2.name); 

            obj2.id = 101;

            obj2.name = "David"; 

            Console.WriteLine("After obj2 change, obj1 Values Id:{0}; Name:{1}:", obj1.id, obj1.name);

            Console.WriteLine("After obj2 change, obj2 Values Id:{0}; Name:{1}:", obj2.id, obj2.name);

            Console.ReadLine();

        }

    }

} 

Employee class implemented the Clone () method by inheriting the ICloneable interface. Object obj2 created by calling Clone() method of object obj1. The output after implementing ICloneable interface shown below.

Even after changing the obj2 values, obj1 values are not getting changed because obj2 is cloned from the obj1 object instead of just copying the reference. System.Object class provides the MemberwiseClone() method to clone the existing object. We can call MemberwiseClone() method in the Clone() method of the ICloneable interface as shown below to clone the object.

using System; 

namespace CSharpCloneableObject

{

    public class Employee : ICloneable

    {

        public int id;

        public string name; 

        public Employee(int id, string name) { this.id = id; this.name = name; } 

        public object Clone()

        {

            return this.MemberwiseClone();

        }

    }

}

 

As of now we just achieve the shallow of an object by using Clone method. The above code works fine if the class has only value type members. We have to make changes to Clone() method if the class contains any reference  type members. For example, change the Employee class to call Company class as shown below.

using System; 

namespace CSharpCloneableObject

{

    public class Employee : ICloneable

    {

        public int id;

        public string name; 

        public Company companyObj = new Company(); 

        public Employee(int id, string name, string companyName)

        {

            this.id = id;

            this.name = name;

            companyObj.Name = companyName;

        } 

        public object Clone()

        {

            return this.MemberwiseClone();

        }

    } 

    public class Company

    {

        public string Name;

    }

} 

using System; 

namespace CSharpCloneableObject

{

    class Program

    {

        static void Main(string[] args)

        {

            Employee obj1 = new Employee(100, "Raj", "ABC"); 

            Employee obj2 = (Employee)obj1.Clone(); 

            Console.WriteLine("Before obj2 change, obj1 Values Id:{0}; Name:{1}; Company:{2}", obj1.id, obj1.name, obj1.companyObj.Name);

            Console.WriteLine("Before obj2 change, obj2 Values Id:{0}; Name:{1}; Company:{2}", obj2.id, obj2.name, obj2.companyObj.Name); 

            obj2.id = 101;

            obj2.name = "David";

            obj2.companyObj.Name = "XYZ";

 

            Console.WriteLine("After obj2 change, obj1 Values Id:{0}; Name:{1}; Company:{2}", obj1.id, obj1.name, obj1.companyObj.Name);

            Console.WriteLine("After obj2 change, obj2 Values Id:{0}; Name:{1}; Company:{2}", obj2.id, obj2.name, obj2.companyObj.Name);

            Console.ReadLine();          

        }

    }

}

 

The above code displays the output as shown below. After cloning if we change the Name of Company class for object obj2, then obj1 Company class Name also will get change because Company is a reference type.

To make a deep clone of an object including reference types also we have to change the Clone() method code as shown below.

using System; 

namespace CSharpCloneableObject

{

    public class Employee : ICloneable

    {

        public int id;

        public string name; 

        public Company companyObj = new Company(); 

        public Employee(int id, string name, string companyName)

        {

            this.id = id;

            this.name = name;

            companyObj.Name = companyName;

        }

        public object Clone()

        {

            Employee newPoint = (Employee)this.MemberwiseClone(); 

            Company currentDesc = new Company();

            currentDesc.Name = this.companyObj.Name;

            newPoint.companyObj = currentDesc;

            return newPoint;

        }

 } 

 public class Company

 {

       public string Name;

 }

} 

Now if you run the code obj1 Company Name will not get change even though obj2 Company Name changes as shown below.

                                                                                                                                                               CSharpCloneableObject.zip