Recently I wanted to create a class that had the ability to clone itself. Here is a simple example class:
internal class CloneableObject
{
private string message;
internal CloneableObject(string message)
{
this.message = message;
}
}
upon implementing the ICloneable interface I noticed the interface specified the return type of object.
#region ICloneable Members
public object Clone()
{
return new CloneableObject("A am a IClonable object");
}
#endregion
My initial opinion was that this wasn't that helpful. You are only ever going to want a CloneableObject returned from CloneableObject.Clone() and I would prefer to avoid casting for runtime type safety and performance.
I can appreciate why IClonable is like this, its not like you can implement your interface in a generic way, e.g.
public interface ICloneable
{
<T> Clone();
}
So, I implemented both ways. One way for those consumers that know it is a ClonableObject and the other way for those who just care that its IClonable.
internal class CloneableObject : ICloneable
{
private string message;
internal string Message { get { return message; } }
internal CloneableObject(string message)
{
this.message = message;
}
internal CloneableObject Clone()
{
return new CloneableObject("I am a CloneableObject");
}
#region ICloneable Members
object ICloneable.Clone()
{
return new CloneableObject("I am ICloneable");
}
#endregion
}
At this point I should point out that I know it should be return new CloneableObject(this.message) as it should be creating a copy of the original not just making up the members, but for this example, it suits.
My next question was, which Clone() gets called when?
The obvious answer is object ICloneable.Clone() when the consumer treats it as a ICloneable object and CloneableObject Clone() when treated as a Cloneable object.
static void Main(string[] args)
{
CloneableObject first = new CloneableObject("original");
ICloneable second = new CloneableObject("original");
Console.WriteLine(first.Clone());
Console.WriteLine(second.Clone());
Console.ReadLine();
}
Best of both worlds in my opinion. I guess the question to ask is why are you implementing ICloneable? Do you consumer classes care?