4

Consider this related question: Deep cloning objects

Is this really the best way to clone an object? (serialize/deserialize). Serialization seems a bit expensive to me.

My idea was to create a second constructor and just assign all variables. Would this approach be faster?

class Test
{

public Test(Test clone)
{
// clone ....
}
}
Community
  • 1
  • 1
Maik Klein
  • 15,548
  • 27
  • 101
  • 197
  • Take a look at this article http://www.codeproject.com/Articles/28952/Shallow-Copy-vs-Deep-Copy-in-NET – Perpetualcoder Mar 15 '12 at 21:59
  • The linked answer starts out mentioning `ICloneable`, and only mentions serialization for when that can't be used. Did you just skip over the first sentence? – Ben Voigt Mar 15 '12 at 21:59
  • You're asking the wrong question. The question should be "which avenue leads to more maintainable code, and does that avenue introduce a performance bottleneck in my application"? – Ed S. Mar 15 '12 at 22:00

6 Answers6

6

It depends on what do you want to clone and why. If a shallow clone is fine, then:

private static T CloneShallow<T>(T i) {
    return
        (T)i.GetType()
            .GetMethod(
                "MemberwiseClone",
                BindingFlags.Instance | BindingFlags.NonPublic
            ).Invoke(i, null);
}

It's the fastest way to clone simple records of any type.

If you need full copy, but it's not time-critical, then:

private static T CloneFull<T>(T i) {
    if (Object.ReferenceEquals(i, null)) return default(T);
    var x = new XmlSerializer(i.GetType());
    using (var m = new MemoryStream()) {
        x.Serialize(m, i);
        m.Seek(0, SeekOrigin.Begin);
        return (T)x.Deserialize(m);
    }
}

The second one is about 70 times slower than the first one.

If you need full copy and the speed is important, consider using protobuf-net as serializer.

There's a lot of answers involving modification of the object you wish to clone, but often you just need to clone a simple record and you don't want to implement anything on it.

And if you wonder how slow CloneFull() is - on my computer (i5 661 @ 3.33GHz) with very simple record it took 360 ticks, which gives 36ns. Which is fast enough in most cases :)

Harry
  • 4,524
  • 4
  • 42
  • 81
2

The key phrase is in the accepted answer

The benefit is that you don't have to concern yourself about cloning everything when an object gets too complex.

The serialisation method works for any object of any complexity. While it might well be overkill for smaller, simpler objects it's a scaleable solution.

If you know your object's not going to change and you only want to clone simple objects then your approach is perfectly acceptable. Though implementing the ICloneable interface is the preferred solution.

Community
  • 1
  • 1
ChrisF
  • 134,786
  • 31
  • 255
  • 325
2

The question to which you are referring talks about generic cloning that works for anything that supports serialization. When you want cloning just for your specific object, simply implement ICloneable.

class Test : ICloneable {
    public object Clone() {
        // clone ....
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 1
    Worth noting that [ICloneable is discouraged to be used in APIs](http://blogs.msdn.com/b/brada/archive/2004/05/03/125427.aspx) – Rowland Shaw Mar 15 '12 at 22:12
  • @RowlandShaw That is true, using `ICloneable` is indeed discouraged, because the contract does not specify the kind of cloning suggested by the interface. However, the OP suggested using a "copy constructor" - style of cloning, which does not generally count as cloning at all. When comparing the two ideas, using `ICloneable` sounds preferable. – Sergey Kalinichenko Mar 15 '12 at 22:21
  • ...as long as you can guarantee that all child objects will support cloning to the same contract. I must admit I'd tend to implement a copy constructor, and have `Clone` call that; It can be easier to deal with in an inheritance hierarchy, too. Going down the Serialise/Deserialise route can lead to *really* bad performance issues. – Rowland Shaw Mar 15 '12 at 22:25
  • Clone() needs to call a constructor anyway, without adding anything a constructor couldn't do. Better avoid the unnecessary overhead of Clone() and have a special constructor just for the purpose of cloning, like `public MyClass(MyClass original): this(/*pass all properties here*/) {}` – Peter Huber Aug 17 '17 at 09:21
1

Serializing is only particularly useful for storing a representation of an object you want to retrieve later/elsewhere. There is an ICloneable interface you should implement if you want an object be able to clone.

C.Evenhuis
  • 25,996
  • 2
  • 58
  • 72
  • 1
    And the MSDN page for IClonable mentions Serialization as one possible method of implementation. – H H Mar 15 '12 at 22:11
  • 2
    Worth noting that [ICloneable is discouraged to be used in APIs](http://blogs.msdn.com/b/brada/archive/2004/05/03/125427.aspx) – Rowland Shaw Mar 15 '12 at 22:16
1

ICloneable

to quote:

Supports cloning, which creates a new instance of a class with the same value as an existing instance. The ICloneable interface contains one member, Clone, which is intended to support cloning beyond that supplied by MemberwiseClone. For more information about cloning, deep versus shallow copies, and examples, see the Object.MemberwiseClone method.

Pete Stensønes
  • 5,595
  • 2
  • 39
  • 62
1

If you are talking about using a custom class, the best way is to implement ICloneable. This way your class can provide a standardized way to clone itself.

There are some times when using a 'copy constructor' can be better, but usually only if you can see that it would be simple, and ICloneable doesn't meet your needs adequately.

Kendall Frey
  • 43,130
  • 20
  • 110
  • 148
  • 4
    Worth noting that [ICloneable is discouraged to be used in APIs](http://blogs.msdn.com/b/brada/archive/2004/05/03/125427.aspx) – Rowland Shaw Mar 15 '12 at 22:15