Monday, August 20, 2012

Cloning Objects in C#

Cloning an object in C# is a surprisingly less straightforward topic than one might think it to be. Cloning is especially needed in crud applications where you want to have the ability to reset data for a form without contacting the database again and without clearing the form. Before I talk of how I used it I’ll just share how I managed the cloning.

Memberwise vs Deep Cloning

The first discovery I made was that there are two forms of cloning available. Shallow and deep. (Are those the real terms? I think I should rebrand this blog as a noob’s take on programming). Shallow cloning aka Memberwise clone is generally enough for any situation. The problem with directly saying

Object a = b (where ‘b’ is of the same Object type as ‘a’) is that as far as basic OOP concepts go you are simply copying the reference. Therefore there’s no point in this clone since any changes simply get reflected in ‘a’. To do a b.clone() call you can implement the icloneable interface but that’s actually an unnecessary step and I’m still trying to find out why bother with it

TODO: Research why one should use the icloneable interface

Back to the matter of memberwise/shallow vs deep cloning. Memberwise cloning basically takes all the individual members of your object and and copies it into a new object. The only real problem here is that you have to make an expensive cast upon returning it since it ends up being returned as an object. Well, relatively expensive anyway but since you realistically won’t be casting a billion objects in a single operation this probably isn’t too bad. The real problem in this method is when an object contains instances of other objects as part of it’s parameter group.

What happens inside when cloning memberwise.

MyClass toBeClonedTo = (MyClass)objectToClone.MemberWiseClone(); results in:

MyClass tobeClonedTo = new MyClass();
tobeClonedTo.paramA = objectToClone.paramA;
tobeClonedTo.paramB = objectToClone.paramB;

But what happens when there is an object inside the object?

toBeClonedTo.MyClass2instance = objectToClone.MyClass2.instance

This ends up just copying the pointer to that object. Which means that if any changes are made to that particular instance it affects the cloned object as well which means whatever you did can be thought of as pretty useless.

Deep Cloning

Deep cloning on the other hand is something that has to be implemented by the programmer and is about cloning every piece of information. Cloning. Not ‘Cloning’. Essentially all you have to do is return a new object of MyClass type with the variables instantiated the way you want them to. If you are in control of all the classes, you might as well call the memberwiseclone method in the other objects as well (eventually everything is made up of basic types) and put those into the constructor.

public MyClass DeepClone()
{
    return new MyClass(this.paramA, this.paramB, (MyClass2)this.MyClass2instance.ShallowClone()
}

Where the MyClass2 will have a method called ShallowClone() that calls the this.MemeberWiseClone() method. Do note that the above example I made of memberwise cloning was incorrect code and was just to illustrate the concept.

And there you have it. Deep Cloning for objects that have instances of other objects in them as parameters. Shallow Cloning or Memberwise Cloning for Objects containing only primitive types.

1 comment:

  1. You should not use the ICloneable inerface. It's deprecated, specifically because it only has a Clone() method on it and the caller can't know if it will deep or shallow copy the object. Cloning in general is usually not needed and is probably a sign of poor design.

    If you find you're doing a lot of cloning, consider making your objects immutable instead and do tree transformations.

    ReplyDelete