Search code examples
c#.net-4.5icloneable

Create copy of Object


I need to clone object (class, not struct) in .net 4.5 (c#).
I found two ways:

  1. Implement ICloneable Interface
  2. Create own clone mechanism like this famous SO answer

I like fist way - it's easier, but I also found Not Implpement ICloneable Interface, but it's very old post and on MSDN I can't find that this interface deprecated.

Could any says me, it is safety to use ICloneable in .net 4.5?


Solution

  • You should not use the IClonable interface.

    Here's a blog from Brad Abrams discussing why not from several years ago. Basically, the reasons are outlined by Tim Schmelter's answer, but this blog is from the horse's mouth.

    In relation to implementing cloning via serialization, there is a slightly better way available now because we can specify StreamingContextStates.Clone to allow the cloning to work better with things like unmanaged handles.

    There's a canonical implementation in "CLR via C# 4th Edition" by Jeffrey Richter which goes like this:

    public static object DeepClone(object original)
    {
        using (var stream = new MemoryStream())
        {
            var formatter = new BinaryFormatter
            {
                Context = new StreamingContext(StreamingContextStates.Clone)
            };
    
            formatter.Serialize(stream, original);
            stream.Position = 0;
    
            return formatter.Deserialize(stream);
        }
    }
    

    Or the strongly typed variant:

    public static T DeepClone<T>(T original)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "original");
        }
    
        if (ReferenceEquals(original, null))
        {
            return default(T);
        }
    
        using (var stream = new MemoryStream())
        {
            var formatter = new BinaryFormatter
            {
                Context = new StreamingContext(StreamingContextStates.Clone)
            };
    
            formatter.Serialize(stream, original);
            stream.Position = 0;
    
            return (T) formatter.Deserialize(stream);
        }
    }
    

    I reckon you should use that (where possible) instead of implementing IClonable.