14

I want to create deep copy method and I found 3 ways to execute it

1-deep copy with pass each property 1 by 1

2-using reflection

3-using serialization

please which of them is the best at performance wise

Mohammed Thabet
  • 21,387
  • 7
  • 27
  • 43

8 Answers8

16

I made graph with comparison of the three methods plus an expression trees method.

enter image description here

For large number of objects is reflection 5x faster and manual code and expression trees are 20x faster than serialization. The best by performance are therefore manual code and expression trees.

Links to used cloning codes (2.-4. used as an extension method):

  1. Manual: Written manually, no link.
  2. Cloning by Serialization
  3. Cloning by Reflection
  4. Cloning by Expression Trees
Community
  • 1
  • 1
frakon
  • 1,948
  • 2
  • 22
  • 26
  • 2
    cloning code using Expression trees that you have posted https://www.codeproject.com/Articles/1111658/Fast-Deep-Copy-by-Expression-Trees-C-Sharp?fid=1907758&select=5469139&fr=1&tid=5467411, is failing with newer versions of .Net framework with a security exception, **Operation could destabilize the runtime**, it is basically an exception due to malformed expression tree, which is used to generate the Func at runtime, please check if you have some solution.In fact I have seen issue only with complex objects with deep hierarchy, simple one easily get copied – Mrinal Kamboj Dec 24 '17 at 14:34
16

The first option, manually deep copying your values, will be the most performant by far.

Reflection will introduce quite a bit of overhead, as it is (relatively) slow to access data.

Serialization is adding a huge cost, as it serializes the data into a temporary structure, then reverses the process to set. This is again, very slow.

The only advantage to option 2 or 3 is that its potentially easier to implement, and reusable across multiple types. The first option has to be hand-written per type, but is much faster (and more efficient in memory usage than option 3, as well).

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • Reflection can be used with Emit/IL and data access speed will be drastically increased. – HABJAN Mar 29 '11 at 18:00
  • 1
    prolly someone miss the arrow :D – Lukasz Madon Mar 29 '11 at 18:01
  • @HABJAN: At that point, you're not using reflection anymore - but introducing a 4th option - Reflection to handle code generation to do the copy directly. However, it'll still never be as fast as a direct copy. – Reed Copsey Mar 29 '11 at 18:03
  • @Reed Copsey: I agree that it will not be as fast as direct copy, but it will be faster than standard reflection and it will save coding time. – HABJAN Mar 29 '11 at 18:14
  • @HABJAN: It depends - if it's only one class, then doing it by hand is probably faster. Also, if you're not doing this clone operation a lot, the overhead of runtime compilation may be higher than the savings in terms of reflection cost. There's a lot of issues that would come into play, since that option has a very large 1 time cost, but then a shorter usage cost. – Reed Copsey Mar 29 '11 at 18:17
  • @Reed Copsey: Check out this article and see speed test image: http://whizzodev.blogspot.com/2008/03/object-cloning-using-il-in-c.html – HABJAN Mar 29 '11 at 18:19
  • @HABJAN: The IL Generation is basically creating a delegate that does what a manual copy would do. The initial generation is going to be slow, but once it's computed and cached, it can be quite fast (almost, but not quite, as fast as a manual copy). If you're doing this thousands of times, that extra overhead will eventually be a wash. (The timings there have some issues, BTW, as they're ignoring JIT issues, which is why the first one is misleading... Had the OP put the "manual" one last, it would be faster still.) – Reed Copsey Mar 29 '11 at 18:26
  • Since manually doing it is the fastest way, you can use the [CGbR project](https://github.com/Toxantron/CGbR#cloneable) to generate that code. – Toxantron May 30 '16 at 07:48
7

Order you listed your possible solutions is correct performance order.

You will get best performance when you write the code to clone each property value manually.

Reflection will have similar result as manually cloning but little slower.

Serialization is the worst scenario. But quickest to implement.

Here is a good article that describes other possible solutions.

So here is a list of all possible cloning methods:

  1. Clone Manually
  2. Clone with MemberwiseClone
  3. Clone with Reflection
  4. Clone with Serialization
  5. Clone with IL
  6. Clone with Extension Methods

Me personally would go with "Clone with IL" as it is slightly faster than reflection and you don't have to clone everything manually.

HABJAN
  • 9,212
  • 3
  • 35
  • 59
  • 8. [Clone with Expression Trees](http://www.codeproject.com/Articles/1111658/Fast-Deep-Copy-by-Expression-Trees-C-Sharp). – frakon Aug 04 '16 at 12:45
2

The best for performance is creating the clone in your code. So the way "1".

TcKs
  • 25,849
  • 11
  • 66
  • 104
1

There's the ICloneable interface. If cloning something ICloneable, using its methods would be best solution

archil
  • 39,013
  • 7
  • 65
  • 82
0

Reflection can be use to produce DynamicMethod which can be more efficient than manually copy (auto-properties can be copied by accessing fields directly breaking scope via skipVisibilityCheck). DynamicMethod offer you a delegate you can keep in static readonly field to clone your object. This is the fast and easy way to do it but not forcely the cleanest. Serialization is slow and not adapted.

Teter28
  • 504
  • 5
  • 8
0

As the author of CGbR I would like to invite you to give it a try for your use case.

All you need is the nuget package and a partial class definition that implements ICloneable. The generated will then create a file next to it with a Clone(bool deep) method.

public partial class Root : ICloneable
{
    public Root(int number)
    {
        _number = number;
    }
    private int _number;

    public Partial[] Partials { get; set; }

    public IList<ulong> Numbers { get; set; }

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

    private Root()
    {
    }
} 

public partial class Root
{
    public Root Clone(bool deep)
    {
        var copy = new Root();
        // All value types can be simply copied
        copy._number = _number; 
        if (deep)
        {
            // In a deep clone the references are cloned 
            var tempPartials = new Partial[Partials.Length];
            for (var i = 0; i < Partials.Length; i++)
            {
                var value = Partials[i];
                value = value.Clone(true);
                tempPartials[i] = value;
            }
            copy.Partials = tempPartials;
            var tempNumbers = new List<ulong>(Numbers.Count);
            for (var i = 0; i < Numbers.Count; i++)
            {
                var value = Numbers[i];
                tempNumbers[i] = value;
            }
            copy.Numbers = tempNumbers;
        }
        else
        {
            // In a shallow clone only references are copied
            copy.Partials = Partials; 
            copy.Numbers = Numbers; 
        }
        return copy;
    }
}

Performance: In a benchmark for a clone we needed at work the compared it to DataContractSerializer and MemoryStream. The generated code is 600x faster.

Toxantron
  • 2,218
  • 12
  • 23
0

Sounds like you've done the hard work of finding the ways to do it, so now you'll have to test them all in your specific situation and find out.

For the most part, it really depends on what data you're serializing

John Gardner
  • 24,225
  • 5
  • 58
  • 76