26

Does anyone want a framework/class which allows me to clone by values .Net objects? I'm only interested with public read/write properties (namely DataContracts), and I don't care if references are resolved correctly (i.e. collecions which contains the same instance of item twice).

I tried serialization trick via DataContractSerializer (serialize to XML and back), wrote reflection-based cloning class (sometimes faster/sometimes slower), and was wondering if someone wrote a helper class which can do this via Emit and not reflection. As for now emitting IL is a little to much for my little brain, but I guess this would be the ultimate solution. Unless someone knows an alternative method which is faster than DataContractSerializer.

wonea
  • 4,783
  • 17
  • 86
  • 139
Karol Kolenda
  • 1,660
  • 2
  • 25
  • 37
  • Are you working with individual objects? Or object trees/graphs? – Marc Gravell May 12 '09 at 10:52
  • Object trees/graphs - like I said, don't care about duplicated references but objects are nested, i.e. they do not contain only flat value properties but also other data contracts. – Karol Kolenda May 12 '09 at 11:46
  • try this: http://valueinjecter.codeplex.com/wikipage?title=Deep%20Cloning&referringTitle=Home – Omu Feb 08 '11 at 08:16
  • If you need the best possible performance and don't mind additional generated code, check out [CGbR Code Generator](https://github.com/Toxantron/CGbR#cloneable) – Toxantron Jun 09 '16 at 06:42
  • DeepCloner by force-net is extremely fast (2021): https://github.com/force-net/DeepCloner – Sire Apr 12 '21 at 13:26
  • Just found this: https://github.com/ReubenBond/DeepCopy . Clones around 20x faster (my simple POCO objects) than the reflection based monstrosity I came up with. – mBardos Feb 04 '22 at 12:23

9 Answers9

24

I have written three deep clone methods for .NET some time ago:

  • One uses the well-known BinaryFormatter technique (though I tweaked it so that objects do not need to be serializable in order to be cloned). This was by far the slowest.

  • For the second I used pure reflection. It was at least 6 times faster than cloning with the BinaryFormatter. This one could also be used on Silverlight and the .NET Compact Framework.

  • The third one uses Linq Expression Trees (for runtime MSIL generation). It is 60 times faster than the BinaryFormatter technique but has a setup time of approximately 2 milliseconds for the first time each class is encountered.

Logarithmic scale illustrating cloning performance

The horizontal axis shows the number of objects cloned (though each cloned object includes several nested objects).

The BinaryFormatter is labeled "Serialization" in the chart. The data series "Reflection" is a custom one that copies fields via GetField()/SetField().

I published all three cloning methods as Open Source here:

http://blog.nuclex-games.com/mono-dotnet/fast-deep-cloning/

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
Cygon
  • 9,444
  • 8
  • 42
  • 50
  • 5
    I'd be curious how serialization busing protobuf-net compares against these three. – Patrick Szalapski Jul 24 '12 at 21:09
  • 1
    I'm getting System.Security.VerificationException: Operation could destabilize the runtime. using ExpressionTreeCloner. Any clue why? – grzegorz_p Mar 20 '14 at 15:58
  • @PatrickSzalapski I've done some benchmarks. Excluding setup time and file system accesses, ProtoBuf-net completes in 2/3rds of the time of the `ReflectionCloner` and is just 5 times slower than the `ExpressionTreeCloner`. – Cygon Feb 04 '15 at 14:32
  • Is the horizontal axis the # of objects? – StayOnTarget Aug 23 '19 at 12:01
  • Is the data series labelled "reflection" the one that was BinaryFormatter? Thanks – StayOnTarget Aug 23 '19 at 12:02
  • @DaveInCaz Yes, horizontal shows the number of objects cloned (though each cloned object includes several nested objects) The BinaryFormatter is labeled "Serialization" here. "Reflection" is a custom one that copies fields via GetField()/SetField(). – Cygon Oct 09 '19 at 05:52
15

If you are talking about an object tree/graph:

Writing specific IL to serialize an object is tricky. IMO, your best bet is to look at a full serialization, like how DataContractSerializer would work - but not necessarily with that engine.

For example, protobuf-net has a Serializer.DeepClone<T> method that might help. It should be faster than DataContractSerializer, at least. At the current time, you need to add some clues for the serializer (even if just [ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]) - however, the current (incomplete) work-in-progress offers POCO support without attributes.


If you are talking about individual objects:

There are fairly simple things you can do here with Expression in .NET 3.5; build a dynamic Expression based on reflection, and call .Compile(). MiscUtil has this already:

DestType clone = PropertyCopy<DestType>.CopyFrom(original);

With .NET 2.0/3.0 (without Expression) you might consider HyperDescriptor for similar purposes.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    Ok, so far I've tested AutoMapper which is actually 4 times slower than DataContract serialization, fast reflections from The Instruction Limit suggested by sambo99 are 2 times faster and protobuf is 3 times faster than DataContract. Marc, can you please elaborate on this: "the current (incomplete) work-in-progress offers POCO support without attributes." I cannot make it work without ProtoContract from featured version of protobuf. Thanks. – Karol Kolenda May 12 '09 at 11:44
  • I did say it was incomplete! Basically, the "lessgenerics" branch (which doesn't work yet; don't try it) has a separate mechanism for defining the members, etc - obviously *defaulting* to attributes as the fallback. So *at some future point* you would be able to use a closed source type by saying "treat this type like so..." - a bit like the massively overloaded ctor to XmlSerializer. – Marc Gravell May 12 '09 at 11:51
  • Actually, if your data-contract specifies the Order on each member, then it will use [DataContract]/[DataMember] happily... – Marc Gravell May 12 '09 at 11:53
  • Yes, I read this in protobuf documentation but it somehow does not work. I mean when I don't specify anything I've got an exception that contract is necessary. When I specified DataContract/DataMember a new object is created but nothing is copied. When use [ProtoContract(ImplicitFields=ImplicitFields.AllPublic)]) everything works as expected. I'm puzzled. – Karol Kolenda May 12 '09 at 11:59
  • Sorry Marc, didn't notice your remark about Order. Everything works fine. – Karol Kolenda May 12 '09 at 12:08
  • @MarcGravell: I'm just wondering whether you still need the proto-buf attributes for the deep clone to work? I'd like to include a deep clone in a library without any overhead for external classes to know about proto-buf. – Ian Feb 21 '12 at 11:43
  • @Ian if it is in-proc, you might find BinaryFormatter simpler. There is some convention-based stuff in protobuf-net, and it can be configured to work without attributes - but I'm not sure it is worth the trouble for arbitrary "external classes" – Marc Gravell Feb 21 '12 at 11:47
  • @MarcGravell: It is in-proc but it's something that I do potentially 1000's of times (because unfortunately I can't make my classes immutable without some quite ugly code) so I was looking for something faster than the BinaryFormatter which is what I currently use. I'd thought about IL cloning but haven't found an example that does this recursively for references so thought protobuf-net might be an easy answer. – Ian Feb 21 '12 at 14:33
10

There are a lot of libraries that do this operation. You can see benchmark results here:

In short words, if you need peformance, do it manually, it really faster. Also, some libraries allows to peform shallow cloning (by the question, it is good variant for you), which is faster. And do not use BinaryFormatter if you need any performance.

Also, @frakon mentions that Expressions trees have same speed as IL Emit, it is slightly incorrect. Expressions Tree is slightly slower, but it can be used in partially trusted app.

Manual 13ms

DeepCloner (IL Emit) 167ms

DeepCloner (Expressions) 267ms

CloneExtensions (Expressions) 560ms

NClone 901ms

Clone.Behave! 8551ms

GeorgeCloney 1996ms

Nuclex.Cloning n/a (Crashed)

FastDeepCloner 1882ms

BinaryFormatter 15000ms

force
  • 132
  • 1
  • 7
5

There is probably no full working cloning code made by IL Emit on the internet.

But IL Emit is of the same speed as code by Expression Trees, because both methods end up with similar compiled lambda copy functions. Expression Trees are approximately 4x faster than Reflection. The best thing is that Expression Trees general cloning function is available on the internet.

One implemetation by expression trees was already mentioned by Cygon. New thoroughly tested implementation can be found in the CodeProject article Fast Deep Copy by Expression Trees (C#).

Use the extension method by

var copy = originalObject.DeepCopyByExpressionTree();
Community
  • 1
  • 1
frakon
  • 1,948
  • 2
  • 22
  • 26
3

Try AutoMapper or BLToolkit Mapping

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288
  • AutoMapper is not recommended for object cloning as its creator himself indicates: https://github.com/AutoMapper/AutoMapper/issues/340 – urig Jul 03 '17 at 11:54
3

I don't know whether this suits your requirements exactly, but you could also create a deep clone using a BinaryFormatter. See this answer to a related question (by Binoj Antony):

public static class GenericCopier<T>
{
    public static T DeepCopy(object objectToCopy)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            binaryFormatter.Serialize(memoryStream, objectToCopy);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return (T) binaryFormatter.Deserialize(memoryStream);
        }
    }
}
Community
  • 1
  • 1
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • 1
    this is considerably slower than dynamic method based serialization. (about 10x slower at least) – Sam Saffron May 12 '09 at 10:17
  • 1
    @sambo99: Is there a performance comparison available? I only found one comparing standard serialization methods (http://developers.de/blogs/damir_dobric/archive/2007/08/05/performance-comparison-of-most-popular-serializes.aspx) – Dirk Vollmar May 12 '09 at 10:29
  • @divo see: http://code.google.com/p/protobuf-net/wiki/Performance .. Marc uses Dynamic Method based serialization in protobuf .net – Sam Saffron May 12 '09 at 10:38
  • 1
    I just added my own benchmark results for three different deep cloning methods to my post. You weren't far off with your 10x slower estimate :) – Cygon Jun 20 '12 at 20:04
1

Dynamic Method based serialization will be fastest. (Generate a dynamic method using light weight codegen and use it for serialization)

You can do 1 method per property/field or one method for the whole object. From my benchmarking doing 1 per property does not give you too much of a performance hit.

See the following code, to see how I do this in Media Browser: http://code.google.com/p/videobrowser/source/browse/trunk/MediaBrowser/Library/Persistance/Serializer.cs

There are also some unit tests there.

There is fast reflection sample on theinstructionlimit that does exactly what you want.

see:

http://theinstructionlimit.com/?p=76

Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
0

The CGbR Code Generator can generate an implementation of ICloneable for you. All you need is the nuget package and a partial class definition that implements ICloneable. The generator will do the rest for you:

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;
    }
}
Toxantron
  • 2,218
  • 12
  • 23
-1

Well! you could write your own Clone Method wich you could specify to ignore or include properties by its attributes. My new library in the link down, uses reflection and FieldInfo to clone the object recursively. i have added it to CodeProject so you will have access to its code soon which you could modify it to your needs.

Try it out its very fast and clean, you will love it.
https://www.nuget.org/packages/FastDeepCloner/1.0.1
or
PM> Install-Package FastDeepCloner

Alen.Toma
  • 4,684
  • 2
  • 14
  • 31