views:

112

answers:

2

I have several different classes that I want to be cloneable: GenericRow, GenericRows, ParticularRow, and ParticularRows. There is the following class hierarchy: GenericRow is the parent of ParticularRow, and GenericRows is the parent of ParticularRows. Each class implements ICloneable because I want to be able to create deep copies of instances of each. I find myself writing the exact same code for Clone() in each class:

object ICloneable.Clone()
{
    object clone;

    using (var stream = new MemoryStream())
    {
        var formatter = new BinaryFormatter();

        // Serialize this object
        formatter.Serialize(stream, this);
        stream.Position = 0;

        // Deserialize to another object
        clone = formatter.Deserialize(stream);
    }

    return clone;
}

I then provide a convenience wrapper method, for example in GenericRows:

public GenericRows Clone()
{
    return (GenericRows)((ICloneable)this).Clone();
}

I am fine with the convenience wrapper methods looking about the same in each class because it's very little code and it does differ from class to class by return type, cast, etc. However, ICloneable.Clone() is identical in all four classes. Can I abstract this somehow so it is only defined in one place? My concern was that if I made some utility class/object extension method, it would not correctly make a deep copy of the particular instance I want copied. Is this a good idea anyway?

+2  A: 

heading into a meeting so only have time to throw some code at you.

public static class Clone
{
    public static T DeepCopyViaBinarySerialization<T>(T record)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, record);
            memoryStream.Position = 0;
            return (T)binaryFormatter.Deserialize(memoryStream);
        }
    }
}

from within the Clone method:

Clone()
{
  Clone.DeepCopyViaBinarySerialization(this);
}
drewbu
Add a `this` to the `T record` parameter declaration and you don't even need a Clone method in each class (i.e. turn DeepCopyViaBinarySerialization into an extension method).
dtb
link for argument against ICloneable: http://blogs.msdn.com/b/brada/archive/2004/05/03/125427.aspx
drewbu
+1  A: 

Implementing ICloneable is not a good idea (see Framework Design Guidelines).

Implementing a Clone method with a BinaryFormatter is.... interesting.

I'd actually recommend to write individual Clone methods for each class, e.g.

public Class1 Clone()
{
    var clone = new Class1();
    clone.ImmutableProperty = this.ImmutableProperty;
    clone.MutableProperty = this.MutableProperty.Clone();
    return clone;
}

Yes, you repeat yourself a lot with this, but it's still the best solution IMHO.

dtb
Lol @ 'interesting'. That's how deep copies were made in the code I was given, and I never bothered to change it.
Sarah Vessels