//
You're reading...
Controls

Clone Object Without ICloneable Implementation

Overview:

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:

System.Reflection

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.

Resolution:

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

Explanation:

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.

Regards,

Shahan

Advertisements

About Shahan Ayyub

Shahan is a Microsoft Certified Professional of .Net. Mostly self taught programmer and a quick learner, who just love to code and always eager to find unique solutions to the common problems. Currently working as an iOS developer.

Discussion

2 thoughts on “Clone Object Without ICloneable Implementation

  1. When I tried it with MS chart object, it throws an exception (about some property that could be read/written, i don’t remember)

    That’s because you are using a A.someproperty = B.someproperty, but there is no check if “someproperty” is readOnly or writeOnly.
    My quick-and-dirty solution was to check if the current property is readable (pInfo.canRead) AND writable (pInfo.canWrite).

    If pInfo.CanWrite And pInfo.CanRead Then _
    pInfo.SetValue[…]

    (all of that inside the for cycle).

    Not sure if this was a correct solution or not, I’m not a coding guru.
    But thank you very much for sharing! It helped a lot!

    Posted by samuele | June 13, 2013, 7:06 pm
    • Thank you for time reading this post and pointing out a modification, will update this post accordingly. Actually i was not offering a production code and intention was to introduce an idea to resolve the issue.

      Glad to see it helps!

      Posted by Shahan Ayyub | June 18, 2013, 6:22 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: