It seems strange when we look at the title that usually experts suggest to clone an object through implementation of IClonable interface. But as I have experience, it is good until we do not have a smart and big application where dozen of relations already exists among the objects and you just need this feature in a part of your application. To just make a clone in a part of your application, it would be great to have some other alternative rather than IClonable interface. My suggestion would be namespace:
Lets try to describe the details with the help of object “Person”.
(I will describe it step by step and provide code samples in VB.Net)
Suppose an instance of Person like this:
Dim personA As New Person personA.FirstName = "abc" personA.LastName = "xyz" PersonA.Skills = "Good problem solving skills" personA.Hobbies = "satisfy my urge-to-code by participating in forums"
A Related ISSUE:
This step is very important where usually the MISTAKE made. We try to clone object the way described below:
Dim newFriend As New Person newFriend = personA newFriend.Hobbies = "Avoid coding, instead crazy about action movies like ‘The Expendables 2’"
From line 2, we expect that we have created a copy of the object “personA” with a new name “newFriend” but it is not actually, instead it passes the reference of the “personA” to “newFriend”. Now at this stage you can feel that “hobbies” of “personA” are now affected due to “newFriend”. So personA’s expectation would be obvious, to have something like “goodfriend” rather than this “newFriend”. what do you think?
In order to resolve this issue we usually implements “IClonable” and creates a new copy of object.
Using “System.Reflection” namespace, you can clone an object in the way i have presented in the below snippet:
Private Function Clone(ByVal source As Object) As Object Dim destObject = Activator.CreateInstance(source.GetType()) For Each fInfo As FieldInfo In source.GetType().GetFields fInfo.SetValue(destObject, fInfo.GetValue(source), BindingFlags.Default, Nothing, Nothing) Next For Each pInfo As PropertyInfo In source.GetType().GetProperties pInfo.SetValue(destObject, pInfo.GetValue(source, Nothing), BindingFlags.Default, Nothing, Nothing, Nothing) Next Return destObject End Function
From the above code snippet, Line 2 instantiates a new object of type “source”. The remaining code iterates and examines the fields and properties of object “source” and sets the value in “destObject”. There is no fear of having an issue as we have discussed in “A Related Issue”.
So, from now this would be sufficient to clone any object:
Dim p3 As Person = Clone(personA) ' this clones an object p3.Hobbies = "Horse Riding" ' no impact of p3.Hobbies on personA.Hobbies
I hope it’s a viable solution to this problem and it will not impact the other existing implementation(s)
A Quick Guide to IClonable Implementation:
In short, change your class “Person” like this:
Public Class Person Implements ICloneable Dim _firstName As String = String.Empty Dim _lastName As String = String.Empty Dim _skills As String = String.Empty Dim _hobbies As String = String.Empty Public Property FirstName() As String Get Return _firstName End Get Set(ByVal value As String) _firstName = value End Set End Property Public Property LastName() As String Get Return _lastName End Get Set(ByVal value As String) _lastName = value End Set End Property Public Property Skills() As String Get Return _skills End Get Set(ByVal value As String) _skills = value End Set End Property Public Property Hobbies() As String Get Return _hobbies End Get Set(ByVal value As String) _hobbies = value End Set End Property Public Function Clone() As Object Implements System.ICloneable.Clone Return MyBase.MemberwiseClone() End Function End Sub
and this would be the method call to use Clone()
Dim p4 As Person = p1.Clone() ' This method clones object using IClonable p4.Skills= "Graphics Designer" ' Here no impact of p4.Skills on p1.Skills
This is how we can creates a copy of any object. I hope you are end up with something you find useful.
Your feedback and suggestions are welcome.