Monday, February 25, 2013

Cloning objects in .NET

In .NET I want to do something like:
// This is illegal in C#
public class PdfDetails : ICloneable<PdfDetails>
{
    public int Id { get; set; }
    public string FileName { get; set; }

    public PdfDetails Clone()
    {
        return MemberwiseClone();
    }
}
But I can't because IClonable is not a generic interface. I remember reading explanation for it in Skeets book or Eric Lipper blog, and it was because in .NET framework before 2.0 there was no generics and since then some of the old interfaces were replaced with generic once, in other cases new generics interfaces were created, and in some cases nothing happened - and ICloneable is an example of this group, there is no support or replacement for generics. So I need to do something like:
public class PdfDetails : ICloneable
{
    public int Id { get; set; }
    public string FileName { get; set; }

    public object Clone()
    {
        return MemberwiseClone();
    }
}
Unfortunately I do not want to return an object type I want to return a PdfDetails type but I can't do it with a non generic interface. So I need to do overloading to create a method that returns a PdfDetails type, the thing that I am really thinking of is something like:
public class PdfDetails : ICloneable
{
    public int Id { get; set; }
    public string FileName { get; set; }

    public object Clone()
    {
        return MemberwiseClone();
    }

    // This is illegal in C#
    public PdfDetails Clone()
    {
     return (PdfDetails) Clone();
    }
}
But I can't do it in C#, because it is not how overloading works here. So I need to do something like:
public class PdfDetails : ICloneable
{
    public int Id { get; set; }
    public string FileName { get; set; }

    // unfortunately this method can not be public
    object ICloneable.Clone()
    {
       return MemberwiseClone();
    }

    public PdfDetails Clone()
    {
        // because ICloneable.Clone() can not be public I can not call it from here
        // instad I need to call again MemberwiseClone() method
        return (PdfDetails)MemberwiseClone();
    }
}
But when you look at the code above you ask a question then why do I really want to implement a ICloneable interface in first place. And I belive, that you don't have to if you don't need to. What I mean is you can go and safely write a code like:
public class PdfDetails 
{
    public int Id { get; set; }
    public string FileName { get; set; }

    public PdfDetails Clone()
    {
        return (PdfDetails)MemberwiseClone();
    }
}
It does the job, but it doesn't inform other programmers that PdfDetails class is supposed to Clone objects. That's why I enjoy writing my own interface:
public interface ICloneable<out T>
{
    T Clone();
}
And than implement it
public class PdfDetails : ICloneable<PdfDetails>
{
    public PdfDetails Clone()
    {
 return (PdfDetails)MemberwiseClone();
    }
}

No comments: