Deep cloning objects
Asked Answered
C

59

2638

I want to do something like:

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = myObj.Clone();

And then make changes to the new object that are not reflected in the original object.

I don't often need this functionality, so when it's been necessary, I've resorted to creating a new object and then copying each property individually, but it always leaves me with the feeling that there is a better or more elegant way of handling the situation.

How can I clone or deep copy an object so that the cloned object can be modified without any changes being reflected in the original object?

Confidant answered 17/9, 2008 at 0:6 Comment(13)
May be useful: "Why Copying an Object is a terrible thing to do?" agiledeveloper.com/articles/cloning072002.htmTuchun
#8026390 Another solution...Ingroup
You should have a look at AutoMapperFimbria
Your solution is far more complex, I got lost reading it... hehehe. I'm using an DeepClone interface. public interface IDeepCloneable<T> { T DeepClone(); }Tuchun
@Pedro77: A concern I have with IDeepCloneable is that not all collections of references to things that can be deep-cloned should be; the proper behavior when cloning a List<T> depends not just upon T, but also upon the purpose of the lists. If none of the items in the lists will ever be exposed to anything which would mutate them, then even if the items within the lists could be cloned, it would be better to copy the references directly.Stereotaxis
This question is also answered here https://mcmap.net/q/9314/-how-do-you-do-a-deep-copy-of-an-object-in-net-duplicate/235715Oakleil
@Tuchun -- Though, interestingly, that article ends up saying to create a clone method on the class, then have it call an internal, private constructor that gets passed this. So copying is turrible [sic], but copying carefully (and the article's definitely worth reading) isn't. ;^)Ebarta
If you need this perhaps you have wrong implementation. And if you use dependency injection it does not make sense at all.Printer
In this end, this question and all the answers are about as useful as "How do I code a class?" There are many answers, but there is no single correct answer despite votes. This is NOT to say that no answer is useful or the question not work asking, but beware of polarized answers. The biggest deficit here is emphasis on providing detailed documentation and for the user/implementer of a class to take responsibility for understanding the details of any copy operation.Hermeneutics
Why not just getting a new instance of it? Or if you wanna copy an object you modified rather than just instantiated you might as well create a method that does all of it, and just call that method twice.Britt
Call the MemberwiseClone method to create a shallow copy of an object, and then assign new objects whose values are the same as the original object to any properties or fields whose values are reference types. The DeepCopy method in the example illustrates this approach. msdn.microsoft.com/en-us/library/…Tehuantepec
Check this Answer: https://mcmap.net/q/10150/-cloning-objects-without-serialization about: Cloning objects without SerializationPrinz
this link might help levelup.gitconnected.com/…Limitless
C
1922

Whereas one approach is to implement the ICloneable interface (described here, so I won't regurgitate), here's a nice deep clone object copier I found on The Code Project a while ago and incorporated it into our code. As mentioned elsewhere, it requires your objects to be serializable.

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
    /// <summary>
    /// Perform a deep copy of the object via serialization.
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>A deep copy of the object.</returns>
    public static T Clone<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", nameof(source));
        }

        // Don't serialize a null object, simply return the default for that object
        if (ReferenceEquals(source, null)) return default;

        using var stream = new MemoryStream();
        IFormatter formatter = new BinaryFormatter();
        formatter.Serialize(stream, source);
        stream.Seek(0, SeekOrigin.Begin);
        return (T)formatter.Deserialize(stream);
    }
}

The idea is that it serializes your object and then deserializes it into a fresh object. The benefit is that you don't have to concern yourself about cloning everything when an object gets too complex.

In case of you prefer to use the new extension methods of C# 3.0, change the method to have the following signature:

public static T Clone<T>(this T source)
{
   // ...
}

Now the method call simply becomes objectBeingCloned.Clone();.

EDIT (January 10 2015) Thought I'd revisit this, to mention I recently started using (Newtonsoft) Json to do this, it should be lighter, and avoids the overhead of [Serializable] tags. (NB @atconway has pointed out in the comments that private members are not cloned using the JSON method)

/// <summary>
/// Perform a deep Copy of the object, using Json as a serialization method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{            
    // Don't serialize a null object, simply return the default for that object
    if (ReferenceEquals(source, null)) return default;

    // initialize inner objects individually
    // for example in default constructor some list property initialized with some values,
    // but in 'source' these items are cleaned -
    // without ObjectCreationHandling.Replace default constructor values will be added to result
    var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
Copal answered 17/9, 2008 at 0:6 Comment(25)
https://mcmap.net/q/9283/-deep-cloning-objects/… has a link to the code above [and references two other such implementations, one of which is more appropriate in my context]Unmentionable
Serialization/deserialization involves significant overhead that isn't necessary. See the ICloneable interface and .MemberWise() clone methods in C#.Necessary
@David, granted, but if the objects are light, and the performance hit when using it is not too high for your requirements, then it is a useful tip. I haven't used it intensively with large amounts of data in a loop, I admit, but I have never seen a single performance concern.Copal
@Copal I like your response because it'll work almost every time, but as an embedded systems guy, and mid-90's x86 assembly language graphics nut, optimization is always on my mind. Just remember that deserialization involves costly string processing and reflection, and that some property types - like Dictionaries - can't be serialized/deserialized. Still, very good response that I upvoted. ("Just remember" is for the peanut gallery).Necessary
I'd simply add that one doesn't always have access to an object to be able to implement an ICloneable interface, so this solution comes in handy.Rafa
Instead of "if (!typeof(T).IsSerializable)" you can write "public static T Clone<T>(T source) where T : ISerializableRorry
@Amir: actually, no: typeof(T).IsSerializable is also true if the type has been marked with the [Serializable] attribute. It doesn't have to implement the ISerializable interface.Cockaleekie
I recommend this method signature: public static T Copy<T>(this T item) where T: ISerializableSpiniferous
As mentioned here you'll have to mark unserializable private fields/events as [NonSerialized] (or [field: NonSerialized]) for this to work.Vidda
@epalm, certainly a passable knowledge of Serialization is required, but it's a fairly easy learning curveCopal
Just thought I'd mention that whilst this method is useful, and I've used it myself many a time, it's not at all compatible with Medium Trust - so watch out if you're writing code that needs compatibility. BinaryFormatter access private fields and thus cannot work in the default permissionset for partial trust environments. You could try another serializer, but make sure your caller knows that the clone may not be perfect if the incoming object relies on private fields.Dirk
#8026390 My solution.Ingroup
@David Lively while I know this isn't any faster: if you serialize to JSON instead you can indeed serialize a dictionary, I do it all the time.Adames
Johnc, to @RubenBartelink 's credit, the right number there would be 8 (I suppose), and not 78611 (though I loved the clever reference to own post). But clearly you were writing this very elegant answer while other people were giving one liners and links and even 3 links for such a topic is already quite a big number to read through.Motorbike
@Cawas Ah, I finally see it now! I have no idea if the votes were as skewed back in the day, but I continue to prefer Ian P's answer as it points to the source (this one didn't originally I'm guessing) and I'm willing to take 2 minutes to pick a strategy when the cited article has a very deep analysis of the different ways of doing it.Unmentionable
@RubenBartelink and how about my brand new answer? :PMotorbike
@PederRice For that very reason, it might not be possible to mark a class as Serializable either. In that case, you'd need a solution which uses reflection.Salvia
The BinaryFormatter is insecure, take a look on official docs: learn.microsoft.com/en-us/dotnet/api/…Divide
The private members are not cloned using the JSON method can be avoid using the nuget package PrivateSetterContractResolverMonolithic
@Necessary I think the .MemberwiseClone() method is deeply undervalued in this post. It is an actual microsoft already existing method which solved my problems. Thank you.Tavares
change "self" to "source" also this fails if we have a child list that contains a reference to the main object. It'll get an infinite loop. You need to add "ReferenceLoopHandling = ReferenceLoopHandling.Ignore" to the settings of both Serialize and Deserialize methods.Wards
What is self ?Amelioration
There is an excellent Nuget package that manages Cloning as C#, in my opinion, should. See https://mcmap.net/q/9283/-deep-cloning-objectsTorquemada
Important note about BinaryFormatter deprecation mentioned hereBerna
"BinaryFormatter serialization methods are obsolete and prohibited in ASP.NET apps". Recommended action Stop using BinaryFormatter in your code. Instead, consider using JsonSerializer or XmlSerializer. The main reason is security related: learn.microsoft.com/en-us/dotnet/standard/serialization/…Margarine
H
433

I wanted a cloner for very simple objects of mostly primitives and lists. If your object is out of the box JSON serializable then this method will do the trick. This requires no modification or implementation of interfaces on the cloned class, just a JSON serializer like JSON.NET.

public static T Clone<T>(T source)
{
    var serialized = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(serialized);
}

Also, you can use this extension method

public static class SystemExtension
{
    public static T Clone<T>(this T source)
    {
        var serialized = JsonConvert.SerializeObject(source);
        return JsonConvert.DeserializeObject<T>(serialized);
    }
}
Hyehyena answered 3/4, 2013 at 13:31 Comment(11)
the solutiojn is even faster than the BinaryFormatter solution, .NET Serialization Performance ComparisonConvention
Thanks for this. I was able to do essentially the same thing with the BSON serializer that ships with the MongoDB driver for C#.Alegre
This is the best way for me, However, I use Newtonsoft.Json.JsonConvert but it is the sameHinge
The JSON approach is Ok for small flat objects, but the original question was about any object, including the deep ones. The NFX.Slim serializer works orders of magnitude faster on any .NET type as long as it does not have delegates and unmanaged pointers, here is the source that works very much like BinaryFormnatter only at least 5 times faster: github.com/aumcode/nfx/blob/master/Source/NFX/Serialization/… The test suite: github.com/aumcode/serbench proves that the only serialier which is faster is Protobuf which lacks type dynamism and referencesDiopside
This does not work when your object is an interface.Thunderhead
Can I add that if you want to serialize custom objects, you will need to decorate all the properties with [DataMember] and the class with [DataContract]Schlesinger
For this to work the object to clone needs to be serializable as already mentioned - this also means for example that it may not have circular dependenciesMisunderstood
I think this is the best solution as the implementation can be applied on most programming languages.Rag
In DeserializeObject() you should add additional options new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace}, because default constructor can change something that's not in the source 🔗Buffer
Valid for Deep clone ?Amelioration
"BinaryFormatter serialization methods are obsolete and prohibited in ASP.NET apps". Recommended action Stop using BinaryFormatter in your code. Instead, consider using JsonSerializer or XmlSerializer. The main reason is security related: learn.microsoft.com/en-us/dotnet/standard/serialization/…Margarine
C
204

The reason not to use ICloneable is not because it doesn't have a generic interface. The reason not to use it is because it's vague. It doesn't make clear whether you're getting a shallow or a deep copy; that's up to the implementer.

Yes, MemberwiseClone makes a shallow copy, but the opposite of MemberwiseClone isn't Clone; it would be, perhaps, DeepClone, which doesn't exist. When you use an object through its ICloneable interface, you can't know which kind of cloning the underlying object performs. (And XML comments won't make it clear, because you'll get the interface comments rather than the ones on the object's Clone method.)

What I usually do is simply make a Copy method that does exactly what I want.

Carnay answered 17/9, 2008 at 1:12 Comment(4)
I'm not clear why ICloneable is considered vague. Given a type like Dictionary(Of T,U), I would expect that ICloneable.Clone should do whatever level of deep and shallow copying is necessary to make the new dictionary be an independent dictionary that contains the same T's and U's (struct contents, and/or object references) as the original. Where's the ambiguity? To be sure, a generic ICloneable(Of T), which inherited ISelf(Of T), which included a "Self" method, would be much better, but I don't see ambiguity on deep vs shallow cloning.Stereotaxis
Your example illustrates the problem. Suppose you have a Dictionary<string, Customer>. Should the cloned Dictionary have the same Customer objects as the original, or copies of those Customer objects? There are reasonable use cases for either one. But ICloneable doesn't make clear which one you'll get. That's why it's not useful.Carnay
@Kyralessa The Microsoft MSDN article actually states this very problem of not knowing if you are requesting a deep or shallow copy.Salvia
The answer from the duplicate #129889 describes Copy extension, based on recursive MembershipCloneUndermine
M
161

After much much reading about many of the options linked here, and possible solutions for this issue, I believe all the options are summarized pretty well at Ian P's link (all other options are variations of those) and the best solution is provided by Pedro77's link on the question comments.

So I'll just copy relevant parts of those 2 references here. That way we can have:

The best thing to do for cloning objects in C sharp!

First and foremost, those are all our options:

The article Fast Deep Copy by Expression Trees has also performance comparison of cloning by Serialization, Reflection and Expression Trees.

Why I choose ICloneable (i.e. manually)

Mr Venkat Subramaniam (redundant link here) explains in much detail why.

All his article circles around an example that tries to be applicable for most cases, using 3 objects: Person, Brain and City. We want to clone a person, which will have its own brain but the same city. You can either picture all problems any of the other methods above can bring or read the article.

This is my slightly modified version of his conclusion:

Copying an object by specifying New followed by the class name often leads to code that is not extensible. Using clone, the application of prototype pattern, is a better way to achieve this. However, using clone as it is provided in C# (and Java) can be quite problematic as well. It is better to provide a protected (non-public) copy constructor and invoke that from the clone method. This gives us the ability to delegate the task of creating an object to an instance of a class itself, thus providing extensibility and also, safely creating the objects using the protected copy constructor.

Hopefully this implementation can make things clear:

public class Person : ICloneable
{
    private final Brain brain; // brain is final since I do not want 
                // any transplant on it once created!
    private int age;
    public Person(Brain aBrain, int theAge)
    {
        brain = aBrain; 
        age = theAge;
    }
    protected Person(Person another)
    {
        Brain refBrain = null;
        try
        {
            refBrain = (Brain) another.brain.clone();
            // You can set the brain in the constructor
        }
        catch(CloneNotSupportedException e) {}
        brain = refBrain;
        age = another.age;
    }
    public String toString()
    {
        return "This is person with " + brain;
        // Not meant to sound rude as it reads!
    }
    public Object clone()
    {
        return new Person(this);
    }
    …
}

Now consider having a class derive from Person.

public class SkilledPerson extends Person
{
    private String theSkills;
    public SkilledPerson(Brain aBrain, int theAge, String skills)
    {
        super(aBrain, theAge);
        theSkills = skills;
    }
    protected SkilledPerson(SkilledPerson another)
    {
        super(another);
        theSkills = another.theSkills;
    }

    public Object clone()
    {
        return new SkilledPerson(this);
    }
    public String toString()
    {
        return "SkilledPerson: " + super.toString();
    }
}

You may try running the following code:

public class User
{
    public static void play(Person p)
    {
        Person another = (Person) p.clone();
        System.out.println(p);
        System.out.println(another);
    }
    public static void main(String[] args)
    {
        Person sam = new Person(new Brain(), 1);
        play(sam);
        SkilledPerson bob = new SkilledPerson(new SmarterBrain(), 1, "Writer");
        play(bob);
    }
}

The output produced will be:

This is person with Brain@1fcc69
This is person with Brain@253498
SkilledPerson: This is person with SmarterBrain@1fef6f
SkilledPerson: This is person with SmarterBrain@209f4e

Observe that, if we keep a count of the number of objects, the clone as implemented here will keep a correct count of the number of objects.

Motorbike answered 26/9, 2012 at 20:18 Comment(10)
MS recommends not using ICloneable for public members. "Because callers of Clone cannot depend on the method performing a predictable cloning operation, we recommend that ICloneable not be implemented in public APIs." msdn.microsoft.com/en-us/library/… However, based on the explanation given by Venkat Subramaniam in your linked article, I think it makes sense to use in this situation as long as the creators of the ICloneable objects have a deep understanding of which properties should be deep vs. shallow copies (i.e. deep copy Brain, shallow copy City)Stickup
First off, I'm far from an expert in this topic (public APIs). I think for once that MS remark makes a lot of sense. And I don't think it's safe to assume the users of that API will have such a deep understanding. So, it only makes sense implementing it on a public API if it really won't matter for whoever is going to use it. I guess having some kind of UML very explicitly making the distinction on each property could help. But I'd like to hear from someone with more experience. :PMotorbike
You can use the CGbR Clone Generator and get a similar result without manually writing the code.Chaffer
Intermediate Language implementation is usefulUndermine
There's no final in C#Klystron
Thanks for the different approaches performance comparison from the article codeproject.com/Articles/1111658/…Lunkhead
@Stickup That goes against the principle that people shouldn't have to "just remember" things. Instead of using ICloneable, it makes more sense to define your own interface and methods to do exactly what you want. Then you can clearly document in the XML comments precisely what kind of cloning/copying it does. Incidentally, in some 15 years of .NET in a variety of jobs and industries I've almost never needed to clone/copy anything.Carnay
@RyanLundy I agree to a certain extent, but I would argue that huge percentage of successful programming is "just remembering/knowing" things (including remembering to add XML comments, which interfaces to use, anit-patterns, etc.). Whether you use iCloneable or iMyCustomDeepClone, you still have to deal with which properties should be deep vs. shallow copies in the implementation of that interface, bc in a lot of cases it isn't going to be all deep or all shallow at the property level. That was the intent of my comment was that whomever implements the interface needs that understanding.Stickup
I'd also like to add AutoMapper to the list. It would be considered as 3rd party tool, but since I find it amazing already, here's another use for it.Teetotalism
extends Person in C# ?Amelioration
S
97

I prefer a copy constructor to a clone. The intent is clearer.

Sloop answered 17/9, 2008 at 0:13 Comment(13)
.Net doesn't have copy constructors.Swimmingly
Sure it does: new MyObject(objToCloneFrom) Just declare a ctor which takes the object to clone as a parameter.Sloop
It's not the same thing. You have to add it to every class manually, and you don't even know if you're garantueeing a deep copy.Slipsheet
+1 for copy ctor. You have to manually write a clone() function for each type of object too, and good luck with that when your class hierarchy gets a few levels deep.Humphreys
With copy constructors you lose hierarchy though. agiledeveloper.com/articles/cloning072002.htmVeliz
I like the copy constructor; but suppose you have an AbstractBaseType, with 3 derived types, each nested such that Type1:AbstractBaseType has a Type2:AbstractBaseType member, which has a Type3:AbstractBaseType member. Now you have to check the types.Otolith
@Otolith : Why should you have to check the types? Just rely on inheritance: pastebin.com/XWGQFBhr ...Belindabelisarius
Descendants may require different logic and will require some if-then or switch logic. Otherwise, you have to provide a corresponding base constructor to deep clone. Clone constructors are just messy.Otolith
@Otolith : <s>Why should you have to check the types? Just rely on inheritance: pastebin.com/XWGQFBhr ...</s> Nevermind, after reading Will's link, i understand the issue you tried to express: members of type AbstractBaseType cannot be cloned via some copy-constructor in ABT, their copies would need to be created through their particular type's copy-constructor...Belindabelisarius
The problem with Copy Constructor's and Clone/Copy hand written methods is maintenance. Maintenance that is prone to error. Imagine a DataContract with 50+ fields. Imagine you then go to add a new field, or fields. It can become a cluster-f* real fast. Any change you make to the class, you must also remember to make to the copy constructor. This is why it is better to leave copying up to something like serialization or reflection. It would be nice if C# would add in the functionality for Deep Copy itself, but I believe they left it out because defining what is a Deep Copy isn't cut and driedSalvia
Using a constructor means Copy/Clone cannot be part of an interfacePhotofluorography
@DaveVandenEynde in C++ you have to add it manually too.en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)Klystron
@SalathielGenèse Me too. See if this helps: https://mcmap.net/q/9283/-deep-cloning-objectsTorquemada
S
50

Simple extension method to copy all the public properties. Works for any objects and does not require class to be [Serializable]. Can be extended for other access level.

public static void CopyTo( this object S, object T )
{
    foreach( var pS in S.GetType().GetProperties() )
    {
        foreach( var pT in T.GetType().GetProperties() )
        {
            if( pT.Name != pS.Name ) continue;
            ( pT.GetSetMethod() ).Invoke( T, new object[] 
            { pS.GetGetMethod().Invoke( S, null ) } );
        }
    };
}
Sprang answered 16/3, 2011 at 11:38 Comment(4)
This, unfortunately, is flawed. It's equivalent to calling objectOne.MyProperty = objectTwo.MyProperty (i.e., it will just copy the reference across). It will not clone the values of the properties.Dirk
to Alex Norcliffe : author of question asked about "copying each property" rather then cloning. in most cases exact duplication of properties is not needed.Sprang
i think about using this method but with recursion. so if the value of a property is a reference, create a new object and call CopyTo again. i just see one problem, that all used classes must have a constructor without parameters. Anybody tried this already? i also wonder if this will actually work with properties containing .net classes like DataRow and DataTable?Sharper
The author asked for a deep clone so they could "make changes to the new object that are not reflected in the original object." This answer creates a shallow clone where any changes to objects within the clone will change the original.Discredit
F
39

I've just created CloneExtensions library project. It performs fast, deep clone using simple assignment operations generated by Expression Tree runtime code compilation.

How to use it?

Instead of writing your own Clone or Copy methods with a tone of assignments between fields and properties make the program do it for yourself, using Expression Tree. GetClone<T>() method marked as extension method allows you to simply call it on your instance:

var newInstance = source.GetClone();

You can choose what should be copied from source to newInstance using CloningFlags enum:

var newInstance 
    = source.GetClone(CloningFlags.Properties | CloningFlags.CollectionItems);

What can be cloned?

  • Primitive (int, uint, byte, double, char, etc.), known immutable types (DateTime, TimeSpan, String) and delegates (including Action, Func, etc)
  • Nullable
  • T[] arrays
  • Custom classes and structs, including generic classes and structs.

Following class/struct members are cloned internally:

  • Values of public, not readonly fields
  • Values of public properties with both get and set accessors
  • Collection items for types implementing ICollection

How fast it is?

The solution is faster then reflection, because members information has to be gathered only once, before GetClone<T> is used for the first time for given type T.

It's also faster than serialization-based solution when you clone more then couple instances of the same type T.

and more...

Read more about generated expressions on documentation.

Sample expression debug listing for List<int>:

.Lambda #Lambda1<System.Func`4[System.Collections.Generic.List`1[System.Int32],CloneExtensions.CloningFlags,System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]],System.Collections.Generic.List`1[System.Int32]]>(
    System.Collections.Generic.List`1[System.Int32] $source,
    CloneExtensions.CloningFlags $flags,
    System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]] $initializers) {
    .Block(System.Collections.Generic.List`1[System.Int32] $target) {
        .If ($source == null) {
            .Return #Label1 { null }
        } .Else {
            .Default(System.Void)
        };
        .If (
            .Call $initializers.ContainsKey(.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32]))
        ) {
            $target = (System.Collections.Generic.List`1[System.Int32]).Call ($initializers.Item[.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32])]
            ).Invoke((System.Object)$source)
        } .Else {
            $target = .New System.Collections.Generic.List`1[System.Int32]()
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)
        ) {
            .Default(System.Void)
        } .Else {
            .Default(System.Void)
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)
        ) {
            .Block() {
                $target.Capacity = .Call CloneExtensions.CloneFactory.GetClone(
                    $source.Capacity,
                    $flags,
                    $initializers)
            }
        } .Else {
            .Default(System.Void)
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)
        ) {
            .Block(
                System.Collections.Generic.IEnumerator`1[System.Int32] $var1,
                System.Collections.Generic.ICollection`1[System.Int32] $var2) {
                $var1 = (System.Collections.Generic.IEnumerator`1[System.Int32]).Call $source.GetEnumerator();
                $var2 = (System.Collections.Generic.ICollection`1[System.Int32])$target;
                .Loop  {
                    .If (.Call $var1.MoveNext() != False) {
                        .Call $var2.Add(.Call CloneExtensions.CloneFactory.GetClone(
                                $var1.Current,
                                $flags,


                         $initializers))
                } .Else {
                    .Break #Label2 { }
                }
            }
            .LabelTarget #Label2:
        }
    } .Else {
        .Default(System.Void)
    };
    .Label
        $target
    .LabelTarget #Label1:
}

}

what has the same meaning like following c# code:

(source, flags, initializers) =>
{
    if(source == null)
        return null;

    if(initializers.ContainsKey(typeof(List<int>))
        target = (List<int>)initializers[typeof(List<int>)].Invoke((object)source);
    else
        target = new List<int>();

    if((flags & CloningFlags.Properties) == CloningFlags.Properties)
    {
        target.Capacity = target.Capacity.GetClone(flags, initializers);
    }

    if((flags & CloningFlags.CollectionItems) == CloningFlags.CollectionItems)
    {
        var targetCollection = (ICollection<int>)target;
        foreach(var item in (ICollection<int>)source)
        {
            targetCollection.Add(item.Clone(flags, initializers));
        }
    }

    return target;
}

Isn't it quite like how you'd write your own Clone method for List<int>?

Fichtean answered 24/12, 2013 at 22:56 Comment(3)
What are the chances of this getting on NuGet? It seems like the best solution. How does it compare to NClone?Salvia
I think this answer should be upvoted more times. Manually implementing ICloneable is tedious and error-prone, using reflection or serialization is slow if performance is important and you need to copy thousands of objects during a short period of time.Ascariasis
Not at all, you wrong about reflection, you should simply cache this properly. Check my answer below https://mcmap.net/q/9283/-deep-cloning-objectsProcure
G
38

If you're already using a 3rd party application like ValueInjecter or Automapper, you can do something like this:

MyObject oldObj; // The existing object to clone

MyObject newObj = new MyObject();
newObj.InjectFrom(oldObj); // Using ValueInjecter syntax

Using this method you don't have to implement ISerializable or ICloneable on your objects. This is common with the MVC/MVVM pattern, so simple tools like this have been created.

see the ValueInjecter deep cloning sample on GitHub.

Gadolinium answered 15/10, 2012 at 17:55 Comment(0)
C
37

Well I was having problems using ICloneable in Silverlight, but I liked the idea of seralization, I can seralize XML, so I did this:

static public class SerializeHelper
{
    //Michael White, Holly Springs Consulting, 2009
    //[email protected]
    public static T DeserializeXML<T>(string xmlData) 
        where T:new()
    {
        if (string.IsNullOrEmpty(xmlData))
            return default(T);

        TextReader tr = new StringReader(xmlData);
        T DocItms = new T();
        XmlSerializer xms = new XmlSerializer(DocItms.GetType());
        DocItms = (T)xms.Deserialize(tr);

        return DocItms == null ? default(T) : DocItms;
    }

    public static string SeralizeObjectToXML<T>(T xmlObject)
    {
        StringBuilder sbTR = new StringBuilder();
        XmlSerializer xmsTR = new XmlSerializer(xmlObject.GetType());
        XmlWriterSettings xwsTR = new XmlWriterSettings();
        
        XmlWriter xmwTR = XmlWriter.Create(sbTR, xwsTR);
        xmsTR.Serialize(xmwTR,xmlObject);
        
        return sbTR.ToString();
    }

    public static T CloneObject<T>(T objClone) 
        where T:new()
    {
        string GetString = SerializeHelper.SeralizeObjectToXML<T>(objClone);
        return SerializeHelper.DeserializeXML<T>(GetString);
    }
}
Carma answered 2/12, 2009 at 17:39 Comment(0)
N
37

The best is to implement an extension method like

public static T DeepClone<T>(this T originalObject)
{ /* the cloning code */ }

and then use it anywhere in the solution by

var copy = anyObject.DeepClone();

We can have the following three implementations:

  1. By Serialization (the shortest code)
  2. By Reflection - 5x faster
  3. By Expression Trees - 20x faster

All linked methods are well working and were deeply tested.

Nee answered 3/8, 2016 at 22:24 Comment(5)
cloning code using Expression trees that you have posted codeproject.com/Articles/1111658/…, 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 copiedLeucocyte
ExpressionTree implementation seems very good. It even works with circular references and private members. No attributes needed. Best answer I've found.Studbook
The best answer, worked very well, you saved my dayTherianthropic
@MrinalKamboj Was there any solution for this error? Since I'm getting it as well, when trying to clone complex object, and can't find a solution so far.Taal
@Taal No I couldn't find a solution at that timeLeucocyte
T
29

DeepCloner: Quick, easy, effective NuGet package to solve cloning

After reading all answers I was surprised no one mentioned this excellent package:

DeepCloner GitHub project

DeepCloner NuGet package

Elaborating a bit on its README, here are the reason why we chose it at work:

  • It can deep or shallow copy
  • In deep cloning all object graph is maintained.
  • Uses code-generation in runtime, as result cloning is blazingly fast
  • Objects copied by internal structure, no methods or ctors called
  • You don't need to mark classes somehow (like Serializable-attribute, or implement interfaces)
  • No requirement to specify object type for cloning. Object can be casted to interface or as an abstract object (e.g. you can clone array of ints as abstract Array or IEnumerable; even null can be cloned without any errors)
  • Cloned object doesn't have any ability to determine that he is clone (except with very specific methods)

Usage:

var deepClone = new { Id = 1, Name = "222" }.DeepClone();
var shallowClone = new { Id = 1, Name = "222" }.ShallowClone();

Performance:

The README contains a performance comparison of various cloning libraries and methods: DeepCloner Performance.

Requirements:

  • .NET 4.0 or higher or .NET Standard 1.3 (.NET Core)
  • Requires Full Trust permission set or Reflection permission (MemberAccess)
Torquemada answered 8/7, 2019 at 10:28 Comment(7)
This question is quite old. I think this answer should go up so people can actually see the value here.Derian
An extra package reference for cloning an object ? Not so nice.Cosma
Feel free to implement one of the million solutions proposed in this thread then. I find this package to be a very convenient solution. I only wish MS would embed a solution equivalent to this in C# or .NET.Torquemada
I used to do custom cloning, like the original questioner, but this package, unlike the various serialization/deserialization solutions, is every bit as fast and worked perfectly out of the box. I don't like the extra package reference either, but for me it was more than worth it.Unfetter
I've tried this, and had an issue with the Model I wanted to clone, and realized it was with something regarding the Interface that Model inherits. Had to give up, and search for another solution, but was really optimistic about this one.Taal
I never had any issue with this, using also very complex objects with many interfaces and inheritance chain. Perhaps you could raise an issue on their package and describe what is wrong? I'd be interested to know. @TaalTorquemada
@Torquemada I have tried with the mentioned class, got an error, and then tried with a simple one which has only one property. Worked with a simple one, then added an Interface that has only one property, ICollection<SomeModel> Comments { get; set;}, and it crashed. Then changed the code from mentioned to ICollection<string> Comments { get; set;} just for testing purposes, and it worked.Taal
H
27

The short answer is you inherit from the ICloneable interface and then implement the .clone function. Clone should do a memberwise copy and perform a deep copy on any member that requires it, then return the resulting object. This is a recursive operation ( it requires that all members of the class you want to clone are either value types or implement ICloneable and that their members are either value types or implement ICloneable, and so on).

For a more detailed explanation on Cloning using ICloneable, check out this article.

The long answer is "it depends". As mentioned by others, ICloneable is not supported by generics, requires special considerations for circular class references, and is actually viewed by some as a "mistake" in the .NET Framework. The serialization method depends on your objects being serializable, which they may not be and you may have no control over. There is still much debate in the community over which is the "best" practice. In reality, none of the solutions are the one-size fits all best practice for all situations like ICloneable was originally interpreted to be.

See the this Developer's Corner article for a few more options (credit to Ian).

Horatius answered 17/9, 2008 at 0:14 Comment(3)
ICloneable doesn't have a generic interface, so it is not recommended to use that interface.Auspice
Your solution works until it needs to handle circular references, then things start to complicate, it's better to try implement deep cloning using deep serialization.Swimmingly
Unfortunately, not all objects are serializable either, so you can't always use that method either. Ian's link is the most comprehensive answer so far.Horatius
B
26
  1. Basically, you need to implement ICloneable interface and then realize object structure copying.
  2. If it's a deep copy of all members, you need to ensure (not relating on solution you choose) that all children are cloneable as well.
  3. Sometimes you need to be aware of some restriction during this process, for example if you copying the ORM objects most of frameworks allow only one object attached to the session and you MUST NOT make clones of this object, or if it's possible you need to care about session attaching of these objects.

Cheers.

Baggywrinkle answered 17/9, 2008 at 0:11 Comment(2)
ICloneable doesn't have a generic interface, so it is not recommended to use that interface.Auspice
Simple and concise answers are the best.Tamasha
T
21

EDIT: project is discontinued

If you want true cloning to unknown types you can take a look at fastclone.

That's expression based cloning working about 10 times faster than binary serialization and maintaining complete object graph integrity.

That means: if you refer multiple times to the same object in your hierachy, the clone will also have a single instance beeing referenced.

There is no need for interfaces, attributes or any other modification to the objects being cloned.

Telencephalon answered 16/2, 2015 at 11:30 Comment(6)
This one seems to be pretty usefulVegetable
It's easier to start working from one code snapshot than for overall system, especially closed one. It's quite understandable that no library can solve all problems with one shot. Some relaxations should be made.Iconoclast
I've tried your solution and it seems to work well, thanks! I think this answer should be upvoted more times. Manually implementing ICloneable is tedious and error-prone, using reflection or serialization is slow if performance is important and you need to copy thousands of objects during a short period of time.Ascariasis
I tried it and it didn't work at all for me. Throws a MemberAccess exception.Narine
It doesn't work with newer versions of .NET and is discontinuedTelencephalon
fastclone worked over 10x faster for me compared to binaryformatter with .NET 4.6.2. Objects cloned are complex types with dictionaries, custom structures, generic lists with nested objects. Everything worked out of the box with no changes to the class.Cherub
H
17

Keep things simple and use AutoMapper as others mentioned, it's a simple little library to map one object to another... To copy an object to another with the same type, all you need is three lines of code:

MyType source = new MyType();
Mapper.CreateMap<MyType, MyType>();
MyType target = Mapper.Map<MyType, MyType>(source);

The target object is now a copy of the source object. Not simple enough? Create an extension method to use everywhere in your solution:

public static T Copy<T>(this T source)
{
    T copy = default(T);
    Mapper.CreateMap<T, T>();
    copy = Mapper.Map<T, T>(source);
    return copy;
}

The extension method can be used as follow:

MyType copy = source.Copy();
Humoral answered 28/5, 2016 at 11:2 Comment(2)
Be careful with this one, it performs really poorly. I ended up switching to johnc answer which is as short as this one and performs a lot better.Fedak
This only does a shallow copy.Studbook
G
14

In general, you implement the ICloneable interface and implement Clone yourself. C# objects have a built-in MemberwiseClone method that performs a shallow copy that can help you out for all the primitives.

For a deep copy, there is no way it can know how to automatically do it.

Gusher answered 17/9, 2008 at 0:9 Comment(1)
ICloneable doesn't have a generic interface, so it is not recommended to use that interface.Auspice
C
14

Disclaimer: I'm the author of the mentioned package.

I was surprised how the top answers to this question in 2019 still use serialization or reflection.

Serialization is limiting (requires attributes, specific constructors, etc.) and is very slow

BinaryFormatter requires the Serializable attribute, JsonConverter requires a parameterless constructor or attributes, neither handle read only fields or interfaces very well and both are 10-30x slower than necessary.

Expression Trees

You can instead use Expression Trees or Reflection.Emit to generate cloning code only once, then use that compiled code instead of slow reflection or serialization.

Having come across the problem myself and seeing no satisfactory solution, I decided to create a package that does just that and works with every type and is a almost as fast as custom written code.

You can find the project on GitHub: https://github.com/marcelltoth/ObjectCloner

Usage

You can install it from NuGet. Either get the ObjectCloner package and use it as:

var clone = ObjectCloner.DeepClone(original);

or if you don't mind polluting your object type with extensions get ObjectCloner.Extensions as well and write:

var clone = original.DeepClone();

Performance

A simple benchmark of cloning a class hierarchy showed performance ~3x faster than using Reflection, ~12x faster than Newtonsoft.Json serialization and ~36x faster than the highly suggested BinaryFormatter.

Chao answered 30/7, 2019 at 20:49 Comment(3)
The reason Serialization is still popular in 2019 is because code generation ONLY works in trusted environments. This means it won't work in Unity or iOS and probably never will. So code generation is non-portable.Northwesterly
I used NewtonSoft's 12.0.3 version, my class's hasn't parameters constructor and it is working for meShalloon
Nice package, I started using it today. Just one thing I noticed, the namespace and class name are same, so to use the static method of class ObjectCloner, I have to explicitly come from the namespace despite using the directive, as for example - ObjectCloner.ObjectCloner.DeepClone(someObject).Cavicorn
T
13

I came up with this to overcome a .NET shortcoming having to manually deep copy List<T>.

I use this:

static public IEnumerable<SpotPlacement> CloneList(List<SpotPlacement> spotPlacements)
{
    foreach (SpotPlacement sp in spotPlacements)
    {
        yield return (SpotPlacement)sp.Clone();
    }
}

And at another place:

public object Clone()
{
    OrderItem newOrderItem = new OrderItem();
    ...
    newOrderItem._exactPlacements.AddRange(SpotPlacement.CloneList(_exactPlacements));
    ...
    return newOrderItem;
}

I tried to come up with oneliner that does this, but it's not possible, due to yield not working inside anonymous method blocks.

Better still, use generic List<T> cloner:

class Utility<T> where T : ICloneable
{
    static public IEnumerable<T> CloneList(List<T> tl)
    {
        foreach (T t in tl)
        {
            yield return (T)t.Clone();
        }
    }
}
Tillo answered 30/9, 2009 at 9:51 Comment(0)
U
12

Q. Why would I choose this answer?

  • Choose this answer if you want the fastest speed .NET is capable of.
  • Ignore this answer if you want a really, really easy method of cloning.

In other words, go with another answer unless you have a performance bottleneck that needs fixing, and you can prove it with a profiler.

10x faster than other methods

The following method of performing a deep clone is:

  • 10x faster than anything that involves serialization/deserialization;
  • Pretty darn close to the theoretical maximum speed .NET is capable of.

And the method ...

For ultimate speed, you can use Nested MemberwiseClone to do a deep copy. Its almost the same speed as copying a value struct, and is much faster than (a) reflection or (b) serialization (as described in other answers on this page).

Note that if you use Nested MemberwiseClone for a deep copy, you have to manually implement a ShallowCopy for each nested level in the class, and a DeepCopy which calls all said ShallowCopy methods to create a complete clone. This is simple: only a few lines in total, see the demo code below.

Here is the output of the code showing the relative performance difference for 100,000 clones:

  • 1.08 seconds for Nested MemberwiseClone on nested structs
  • 4.77 seconds for Nested MemberwiseClone on nested classes
  • 39.93 seconds for Serialization/Deserialization

Using Nested MemberwiseClone on a class almost as fast as copying a struct, and copying a struct is pretty darn close to the theoretical maximum speed .NET is capable of.

Demo 1 of shallow and deep copy, using classes and MemberwiseClone:
  Create Bob
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Clone Bob >> BobsSon
  Adjust BobsSon details
    BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Elapsed time: 00:00:04.7795670,30000000

Demo 2 of shallow and deep copy, using structs and value copying:
  Create Bob
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Clone Bob >> BobsSon
  Adjust BobsSon details:
    BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Elapsed time: 00:00:01.0875454,30000000

Demo 3 of deep copy, using class and serialize/deserialize:
  Elapsed time: 00:00:39.9339425,30000000

To understand how to do a deep copy using MemberwiseCopy, here is the demo project that was used to generate the times above:

// Nested MemberwiseClone example. 
// Added to demo how to deep copy a reference class.
[Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization.
public class Person
{
    public Person(int age, string description)
    {
        this.Age = age;
        this.Purchase.Description = description;
    }
    [Serializable] // Not required if using MemberwiseClone
    public class PurchaseType
    {
        public string Description;
        public PurchaseType ShallowCopy()
        {
            return (PurchaseType)this.MemberwiseClone();
        }
    }
    public PurchaseType Purchase = new PurchaseType();
    public int Age;
    // Add this if using nested MemberwiseClone.
    // This is a class, which is a reference type, so cloning is more difficult.
    public Person ShallowCopy()
    {
        return (Person)this.MemberwiseClone();
    }
    // Add this if using nested MemberwiseClone.
    // This is a class, which is a reference type, so cloning is more difficult.
    public Person DeepCopy()
    {
            // Clone the root ...
        Person other = (Person) this.MemberwiseClone();
            // ... then clone the nested class.
        other.Purchase = this.Purchase.ShallowCopy();
        return other;
    }
}
// Added to demo how to copy a value struct (this is easy - a deep copy happens by default)
public struct PersonStruct
{
    public PersonStruct(int age, string description)
    {
        this.Age = age;
        this.Purchase.Description = description;
    }
    public struct PurchaseType
    {
        public string Description;
    }
    public PurchaseType Purchase;
    public int Age;
    // This is a struct, which is a value type, so everything is a clone by default.
    public PersonStruct ShallowCopy()
    {
        return (PersonStruct)this;
    }
    // This is a struct, which is a value type, so everything is a clone by default.
    public PersonStruct DeepCopy()
    {
        return (PersonStruct)this;
    }
}
// Added only for a speed comparison.
public class MyDeepCopy
{
    public static T DeepCopy<T>(T obj)
    {
        object result = null;
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;
            result = (T)formatter.Deserialize(ms);
            ms.Close();
        }
        return (T)result;
    }
}

Then, call the demo from main:

void MyMain(string[] args)
{
    {
        Console.Write("Demo 1 of shallow and deep copy, using classes and MemberwiseCopy:\n");
        var Bob = new Person(30, "Lamborghini");
        Console.Write("  Create Bob\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Console.Write("  Clone Bob >> BobsSon\n");
        var BobsSon = Bob.DeepCopy();
        Console.Write("  Adjust BobsSon details\n");
        BobsSon.Age = 2;
        BobsSon.Purchase.Description = "Toy car";
        Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
        Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Debug.Assert(Bob.Age == 30);
        Debug.Assert(Bob.Purchase.Description == "Lamborghini");
        var sw = new Stopwatch();
        sw.Start();
        int total = 0;
        for (int i = 0; i < 100000; i++)
        {
            var n = Bob.DeepCopy();
            total += n.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
    }
    {               
        Console.Write("Demo 2 of shallow and deep copy, using structs:\n");
        var Bob = new PersonStruct(30, "Lamborghini");
        Console.Write("  Create Bob\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Console.Write("  Clone Bob >> BobsSon\n");
        var BobsSon = Bob.DeepCopy();
        Console.Write("  Adjust BobsSon details:\n");
        BobsSon.Age = 2;
        BobsSon.Purchase.Description = "Toy car";
        Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
        Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);                
        Debug.Assert(Bob.Age == 30);
        Debug.Assert(Bob.Purchase.Description == "Lamborghini");
        var sw = new Stopwatch();
        sw.Start();
        int total = 0;
        for (int i = 0; i < 100000; i++)
        {
            var n = Bob.DeepCopy();
            total += n.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
    }
    {
        Console.Write("Demo 3 of deep copy, using class and serialize/deserialize:\n");
        int total = 0;
        var sw = new Stopwatch();
        sw.Start();
        var Bob = new Person(30, "Lamborghini");
        for (int i = 0; i < 100000; i++)
        {
            var BobsSon = MyDeepCopy.DeepCopy<Person>(Bob);
            total += BobsSon.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n", sw.Elapsed, total);
    }
    Console.ReadKey();
}

Again, note that if you use Nested MemberwiseClone for a deep copy, you have to manually implement a ShallowCopy for each nested level in the class, and a DeepCopy which calls all said ShallowCopy methods to create a complete clone. This is simple: only a few lines in total, see the demo code above.

Value types vs. References Types

Note that when it comes to cloning an object, there is is a big difference between a "struct" and a "class":

  • If you have a "struct", it's a value type so you can just copy it, and the contents will be cloned (but it will only make a shallow clone unless you use the techniques in this post).
  • If you have a "class", it's a reference type, so if you copy it, all you are doing is copying the pointer to it. To create a true clone, you have to be more creative, and use differences between value types and references types which creates another copy of the original object in memory.

See differences between value types and references types.

Checksums to aid in debugging

  • Cloning objects incorrectly can lead to very difficult-to-pin-down bugs. In production code, I tend to implement a checksum to double check that the object has been cloned properly, and hasn't been corrupted by another reference to it. This checksum can be switched off in Release mode.
  • I find this method quite useful: often, you only want to clone parts of the object, not the entire thing.

Really useful for decoupling many threads from many other threads

One excellent use case for this code is feeding clones of a nested class or struct into a queue, to implement the producer / consumer pattern.

  • We can have one (or more) threads modifying a class that they own, then pushing a complete copy of this class into a ConcurrentQueue.
  • We then have one (or more) threads pulling copies of these classes out and dealing with them.

This works extremely well in practice, and allows us to decouple many threads (the producers) from one or more threads (the consumers).

And this method is blindingly fast too: if we use nested structs, it's 35x faster than serializing/deserializing nested classes, and allows us to take advantage of all of the threads available on the machine.

Update

Apparently, ExpressMapper is as fast, if not faster, than hand coding such as above. I might have to see how they compare with a profiler.

Unmoor answered 4/7, 2015 at 17:24 Comment(2)
If you copy a struct you get a shallow copy, you might still need specific implementation for a deep copy.Moschatel
@Lasse V. Karlsen. Yes, you're absolutely correct, I've updated the answer to make this clearer. This method can be used to make deep copies of structs and classes. You can run the included example demo code to show how its done, it has an example of deep cloning a nested struct, and another example of deep cloning a nested class.Unmoor
W
10

Create an extension:

public static T Clone<T>(this T theObject)
{
    string jsonData = JsonConvert.SerializeObject(theObject);
    return JsonConvert.DeserializeObject<T>(jsonData);
}

And call it like this:

NewObject = OldObject.Clone();
Weiser answered 24/6, 2020 at 21:24 Comment(0)
R
9

I've seen it implemented through reflection as well. Basically there was a method that would iterate through the members of an object and appropriately copy them to the new object. When it reached reference types or collections I think it did a recursive call on itself. Reflection is expensive, but it worked pretty well.

Reyna answered 19/10, 2010 at 13:1 Comment(0)
M
9

Here is a deep copy implementation:

public static object CloneObject(object opSource)
{
    //grab the type and create a new instance of that type
    Type opSourceType = opSource.GetType();
    object opTarget = CreateInstanceOfType(opSourceType);

    //grab the properties
    PropertyInfo[] opPropertyInfo = opSourceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    //iterate over the properties and if it has a 'set' method assign it from the source TO the target
    foreach (PropertyInfo item in opPropertyInfo)
    {
        if (item.CanWrite)
        {
            //value types can simply be 'set'
            if (item.PropertyType.IsValueType || item.PropertyType.IsEnum || item.PropertyType.Equals(typeof(System.String)))
            {
                item.SetValue(opTarget, item.GetValue(opSource, null), null);
            }
            //object/complex types need to recursively call this method until the end of the tree is reached
            else
            {
                object opPropertyValue = item.GetValue(opSource, null);
                if (opPropertyValue == null)
                {
                    item.SetValue(opTarget, null, null);
                }
                else
                {
                    item.SetValue(opTarget, CloneObject(opPropertyValue), null);
                }
            }
        }
    }
    //return the new item
    return opTarget;
}
Mich answered 6/9, 2011 at 7:38 Comment(4)
This looks like memberwise clone because does not aware of reference type propertiesPincus
If you want blindingly fast performance, don't go for this implementation: it uses reflection, so it won't be that fast. Conversely, "premature optmization is the of all evil", so ignore the performance side until after you've run a profiler.Unmoor
CreateInstanceOfType is not defined?Mb
It fails on interger: "Non-static method requires a target."Multure
B
8

As I couldn't find a cloner that meets all my requirements in different projects, I created a deep cloner that can be configured and adapted to different code structures instead of adapting my code to meet the cloners requirements. Its achieved by adding annotations to the code that shall be cloned or you just leave the code as it is to have the default behaviour. It uses reflection, type caches and is based on fasterflect. The cloning process is very fast for a huge amount of data and a high object hierarchy (compared to other reflection/serialization based algorithms).

https://github.com/kalisohn/CloneBehave

Also available as a nuget package: https://www.nuget.org/packages/Clone.Behave/1.0.0

For example: The following code will deepClone Address, but only perform a shallow copy of the _currentJob field.

public class Person 
{
  [DeepClone(DeepCloneBehavior.Shallow)]
  private Job _currentJob;      

  public string Name { get; set; }

  public Job CurrentJob 
  { 
    get{ return _currentJob; }
    set{ _currentJob = value; }
  }

  public Person Manager { get; set; }
}

public class Address 
{      
  public Person PersonLivingHere { get; set; }
}

Address adr = new Address();
adr.PersonLivingHere = new Person("John");
adr.PersonLivingHere.BestFriend = new Person("James");
adr.PersonLivingHere.CurrentJob = new Job("Programmer");

Address adrClone = adr.Clone();

//RESULT
adr.PersonLivingHere == adrClone.PersonLivingHere //false
adr.PersonLivingHere.Manager == adrClone.PersonLivingHere.Manager //false
adr.PersonLivingHere.CurrentJob == adrClone.PersonLivingHere.CurrentJob //true
adr.PersonLivingHere.CurrentJob.AnyProperty == adrClone.PersonLivingHere.CurrentJob.AnyProperty //true
Burcham answered 25/1, 2016 at 17:45 Comment(0)
C
8

Code Generator

We have seen a lot of ideas from serialization over manual implementation to reflection and I want to propose a totally different approach using the CGbR Code Generator. The generate clone method is memory and CPU efficient and therefor 300x faster as the standard DataContractSerializer.

All you need is a partial class definition with ICloneable and the generator does the rest:

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.Add(value);
            }
            copy.Numbers = tempNumbers;
        }
        else
        {
            // In a shallow clone only references are copied
            copy.Partials = Partials; 
            copy.Numbers = Numbers; 
        }
        return copy;
    }
}

Note: Latest version has a more null checks, but I left them out for better understanding.

Chaffer answered 9/6, 2016 at 20:56 Comment(0)
V
7

I like Copyconstructors like that:

    public AnyObject(AnyObject anyObject)
    {
        foreach (var property in typeof(AnyObject).GetProperties())
        {
            property.SetValue(this, property.GetValue(anyObject));
        }
        foreach (var field in typeof(AnyObject).GetFields())
        {
            field.SetValue(this, field.GetValue(anyObject));
        }
    }

If you have more things to copy add them

Vegetable answered 6/3, 2015 at 13:48 Comment(0)
P
7

This method solved the problem for me:

private static MyObj DeepCopy(MyObj source)
        {

            var DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };

            return JsonConvert.DeserializeObject<MyObj >(JsonConvert.SerializeObject(source), DeserializeSettings);

        }

Use it like this: MyObj a = DeepCopy(b);

Pongee answered 12/4, 2016 at 13:43 Comment(0)
B
7

Here a solution fast and easy that worked for me without relaying on Serialization/Deserialization.

public class MyClass
{
    public virtual MyClass DeepClone()
    {
        var returnObj = (MyClass)MemberwiseClone();
        var type = returnObj.GetType();
        var fieldInfoArray = type.GetRuntimeFields().ToArray();

        foreach (var fieldInfo in fieldInfoArray)
        {
            object sourceFieldValue = fieldInfo.GetValue(this);
            if (!(sourceFieldValue is MyClass))
            {
                continue;
            }

            var sourceObj = (MyClass)sourceFieldValue;
            var clonedObj = sourceObj.DeepClone();
            fieldInfo.SetValue(returnObj, clonedObj);
        }
        return returnObj;
    }
}

EDIT: requires

    using System.Linq;
    using System.Reflection;

That's How I used it

public MyClass Clone(MyClass theObjectIneededToClone)
{
    MyClass clonedObj = theObjectIneededToClone.DeepClone();
}
Blast answered 29/7, 2016 at 13:44 Comment(0)
S
6

Follow these steps:

  • Define an ISelf<T> with a read-only Self property that returns T, and ICloneable<out T>, which derives from ISelf<T> and includes a method T Clone().
  • Then define a CloneBase type which implements a protected virtual generic VirtualClone casting MemberwiseClone to the passed-in type.
  • Each derived type should implement VirtualClone by calling the base clone method and then doing whatever needs to be done to properly clone those aspects of the derived type which the parent VirtualClone method hasn't yet handled.

For maximum inheritance versatility, classes exposing public cloning functionality should be sealed, but derive from a base class which is otherwise identical except for the lack of cloning. Rather than passing variables of the explicit clonable type, take a parameter of type ICloneable<theNonCloneableType>. This will allow a routine that expects a cloneable derivative of Foo to work with a cloneable derivative of DerivedFoo, but also allow the creation of non-cloneable derivatives of Foo.

Stereotaxis answered 7/12, 2011 at 21:24 Comment(0)
N
6

Shortest way but need dependency:

using Newtonsoft.Json;
    public static T Clone<T>(T source) =>
        JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
Nuthatch answered 21/11, 2019 at 12:59 Comment(0)
P
6

C# 9.0 is introducing the with keyword that requires a record (Thanks Mark Nading). This should allow very simple object cloning (and mutation if required) with very little boilerplate, but only with a record.

You cannot seem to be able to clone (by value) a class by putting it into a generic record;

using System;
                
public class Program
{
    public class Example
    {
        public string A { get; set; }
    }
    
    public record ClonerRecord<T>(T a)
    {
    }

    public static void Main()
    {
        var foo = new Example {A = "Hello World"};
        var bar = (new ClonerRecord<Example>(foo) with {}).a;
        foo.A = "Goodbye World :(";
        Console.WriteLine(bar.A);
    }
}

This writes "Goodbye World :("- the string was copied by reference (undesired). https://dotnetfiddle.net/w3IJgG

(Incredibly, the above works correctly with a struct! https://dotnetfiddle.net/469NJv)

But cloning a record does seem to work as indented, cloning by value.

using System;

public class Program
{
    public record Example
    {
        public string A { get; set; }
    }
    
    public static void Main()
    {
        var foo = new Example {A = "Hello World"};
        var bar = foo with {};
        foo.A = "Goodbye World :(";
        Console.WriteLine(bar.A);
    }
}

This returns "Hello World", the string was copied by value! https://dotnetfiddle.net/MCHGEL

More information can be found on the blog post:

https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression

Parados answered 5/8, 2021 at 9:24 Comment(2)
Based on what I've read, this is only for the new "record" type. One of us should really just try this out in .net fiddle :PManriquez
@MarkNadig I hadn't even noticed that! It looks like using a record to clone a class doesn't work- dotnetfiddle.net/w3IJgG; But Cloning for a flat record does appear to copy by value! dotnetfiddle.net/MCHGELParados
K
6

In the codebase I am working with, we had a copy of the file ObjectExtensions.cs from the GitHub project Burtsev-Alexey/net-object-deep-copy. It is 9 years old. It worked, although we later realized it was very slow for larger object structures.

Instead, we found a fork of the file ObjectExtensions.cs in the GitHub project jpmikkers/Baksteen.Extensions.DeepCopy. A deep copy operation of a large data structure that previously took us about 30 minutes, now feels almost instantaneous.

This improved version has the following documentation:

C# extension method for fast object cloning.

This is a speed-optimized fork of Alexey Burtsev's deep copier. Depending on your usecase, this will be 2x - 3x faster than the original. It also fixes some bugs which are present in the original code. Compared to the classic binary serialization/deserialization deep clone technique, this version is about seven times faster (the more arrays your objects contain, the bigger the speedup factor).

The speedup is achieved via the following techniques:

  • object reflection results are cached
  • don't deep copy primitives or immutable structs & classes (e.g. enum and string)
  • to improve locality of reference, process the 'fast' dimensions or multidimensional arrays in the inner loops
  • use a compiled lamba expression to call MemberwiseClone

How to use:

using Baksteen.Extensions.DeepCopy;
...
var myobject = new SomeClass();
...
var myclone = myobject.DeepCopy()!;    // creates a new deep copy of the original object 

Note: the exclamation mark (null-forgiving operator) is only required if you enabled nullable referency types in your project

Khudari answered 2/9, 2022 at 9:52 Comment(3)
Thank you. This worked for me in .Net 8 and with a very sophisticated and large object graph.Dalia
I also use this extension but once it failed with fairly simple object, just few primitive properties + CancellationTokenSource. This cts causes infinite recursive call during deepcopying which hard to catch because try/catch does not work for it, VS just stops debugging with access violation error. Unfortunately, author closed "Issues" on the GitHub so it's not possible to get in contact.Spoof
@Spoof oh I didn't realize my issues tab wasn't showing! I fixed that just now. I'll have a look at the CancellationTokenSource asap (feel free to create an issue if you spot any other problems)Godspeed
P
5

Ok, there are some obvious example with reflection in this post, BUT reflection is usually slow, until you start to cache it properly.

if you'll cache it properly, than it'll deep clone 1000000 object by 4,6s (measured by Watcher).

static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();

than you take cached properties or add new to dictionary and use them simply

foreach (var prop in propList)
{
        var value = prop.GetValue(source, null);   
        prop.SetValue(copyInstance, value, null);
}

full code check in my post in another answer

https://mcmap.net/q/9328/-how-do-i-clone-a-generic-list-in-c

Procure answered 19/12, 2015 at 8:17 Comment(1)
Calling prop.GetValue(...) is still reflection and can't be cached. In an expression tree its compiled though, so fasterWendeline
N
5

As nearly all of the answers to this question have been unsatisfactory or plainly don't work in my situation, I have authored AnyClone which is entirely implemented with reflection and solved all of the needs here. I was unable to get serialization to work in a complicated scenario with complex structure, and IClonable is less than ideal - in fact it shouldn't even be necessary.

Standard ignore attributes are supported using [IgnoreDataMember], [NonSerialized]. Supports complex collections, properties without setters, readonly fields etc.

I hope it helps someone else out there who ran into the same problems I did.

Narine answered 16/11, 2018 at 6:40 Comment(1)
With AnyClone I just installed the NuGet Package, called .Clone() and it worked very well on a Blazor project here!Gingili
G
4

I have created a version of the accepted answer that works with both '[Serializable]' and '[DataContract]'. It has been a while since I wrote it, but if I remember correctly [DataContract] needed a different serializer.

Requires System, System.IO, System.Runtime.Serialization, System.Runtime.Serialization.Formatters.Binary, System.Xml;

public static class ObjectCopier
{

    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[Serializable]' or '[DataContract]'
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T Clone<T>(T source)
    {
        if (typeof(T).IsSerializable == true)
        {
            return CloneUsingSerializable<T>(source);
        }

        if (IsDataContract(typeof(T)) == true)
        {
            return CloneUsingDataContracts<T>(source);
        }

        throw new ArgumentException("The type must be Serializable or use DataContracts.", "source");
    }


    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[Serializable]'
    /// </summary>
    /// <remarks>
    /// Found on https://mcmap.net/q/9283/-deep-cloning-objects
    /// Uses code found on CodeProject, which allows free use in third party apps
    /// - http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
    /// </remarks>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T CloneUsingSerializable<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "source");
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }


    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[DataContract]'
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T CloneUsingDataContracts<T>(T source)
    {
        if (IsDataContract(typeof(T)) == false)
        {
            throw new ArgumentException("The type must be a data contract.", "source");
        }

        // ** Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        DataContractSerializer dcs = new DataContractSerializer(typeof(T));
        using(Stream stream = new MemoryStream())
        {
            using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
            {
                dcs.WriteObject(writer, source);
                writer.Flush();
                stream.Seek(0, SeekOrigin.Begin);
                using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
                {
                    return (T)dcs.ReadObject(reader);
                }
            }
        }
    }


    /// <summary>
    /// Helper function to check if a class is a [DataContract]
    /// </summary>
    /// <param name="type">The type of the object to check.</param>
    /// <returns>Boolean flag indicating if the class is a DataContract (true) or not (false) </returns>
    public static bool IsDataContract(Type type)
    {
        object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false);
        return attributes.Length == 1;
    }

} 
Golden answered 11/4, 2014 at 16:6 Comment(0)
E
3

To clone your class object you can use the Object.MemberwiseClone method,

just add this function to your class :

public class yourClass
{
    // ...
    // ...

    public yourClass DeepCopy()
    {
        yourClass othercopy = (yourClass)this.MemberwiseClone();
        return othercopy;
    }
}

then to perform a deep independant copy, just call the DeepCopy method :

yourClass newLine = oldLine.DeepCopy();

hope this helps.

Embarkment answered 25/4, 2014 at 9:39 Comment(3)
MemberwiseClone method creates a shallow copy NOT a deep copy. msdn.microsoft.com/en-us/library/…Jenks
@Jenks important comment as actual code Do shallow copy, Here good article about Clone and examples for every type geeksforgeeks.org/shallow-copy-and-deep-copy-in-c-sharpLovesome
So far this is working for my situation. Thank you.Wolsey
B
3

I think you can try this.

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = new MyObject(myObj); //DeepClone it
Borrell answered 19/8, 2016 at 16:47 Comment(1)
Two issues - first there's no automatic constructor in c# that will take an object of the same type so new MyObject(myObj); will probably error. Second if you created such a constructor, it would either be a shallow clone or you'd have to use similar constructors every step into properties of the object to clone contained objects and collection.Discredit
A
3

A mapper performs a deep-copy. Foreach member of your object it creates a new object and assign all of its values. It works recursively on each non-primitive inner member.

I suggest you one of the fastest, currently actively developed ones. I suggest UltraMapper https://github.com/maurosampietro/UltraMapper

Nuget packages: https://www.nuget.org/packages/UltraMapper/

Almsman answered 23/4, 2017 at 9:16 Comment(1)
A link to a solution is welcome, but please ensure your answer is useful without it: add context around the link so your fellow users will have some idea what it is and why it’s there, then quote the most relevant part of the page you're linking to in case the target page is unavailable. Answers that are little more than a link may be deleted.Evidence
P
3

I’ll use the below simple way to implement this. Just create an abstract class and implement method to serialize and deserialize again and return.

public abstract class CloneablePrototype<T>
{
    public T DeepCopy()
    {
        string result = JsonConvert.SerializeObject(this);
        return JsonConvert.DeserializeObject<T>(result);
    }
}
public class YourClass : CloneablePrototype< YourClass>
…
…
…

And the use it like this to create deep copy.

YourClass newObj = (YourClass)oldObj.DeepCopy();

This solution is easy to extend as well if you need to implement the shallow copy method as well.

Just implement a new method in the abstract class.

public T ShallowCopy()
{
    return (T)this.MemberwiseClone();
}
Poleyn answered 28/1, 2022 at 19:25 Comment(0)
L
3

Besides some of the brilliant answers here, what you can do in C# 9.0 & higher, is the following (assuming you can convert your class to a record):

record Record
{
    public int Property1 { get; set; }

    public string Property2 { get; set; }
}

And then, simply use with operator to copy values of one object to the new one.

var object1 = new Record()
{
    Property1 = 1,
    Property2 = "2"
};

var object2 = object1 with { };
// object2 now has Property1 = 1 & Property2 = "2"

I hope this helps :)

Lustrate answered 13/4, 2022 at 20:33 Comment(0)
V
2

If your Object Tree is Serializeable you could also use something like this

static public MyClass Clone(MyClass myClass)
{
    MyClass clone;
    XmlSerializer ser = new XmlSerializer(typeof(MyClass), _xmlAttributeOverrides);
    using (var ms = new MemoryStream())
    {
        ser.Serialize(ms, myClass);
        ms.Position = 0;
        clone = (MyClass)ser.Deserialize(ms);
    }
    return clone;
}

be informed that this Solution is pretty easy but it's not as performant as other solutions may be.

And be sure that if the Class grows, there will still be only those fields cloned, which also get serialized.

Vegetable answered 20/4, 2015 at 13:51 Comment(0)
I
2

It's unbelievable how much effort you can spend with IClonable interface - especially if you have heavy class hierarchies. Also MemberwiseClone works somehow oddly - it does not exactly clone even normal List type kind of structures.

And of course most interesting dilemma for serialization is to serialize back references - e.g. class hierarchies where you have child-parent relationships. I doubt that binary serializer will be able to help you in this case. (It will end up with recursive loops + stack overflow).

I somehow liked solution proposed here: How do you do a deep copy of an object in .NET (C# specifically)?

however - it did not support Lists, added that support, also took into account re-parenting. For parenting only rule which I have made that field or property should be named "parent", then it will be ignored by DeepClone. You might want to decide your own rules for back-references - for tree hierarchies it might be "left/right", etc...

Here is whole code snippet including test code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;

namespace TestDeepClone
{
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
            a.name = "main_A";
            a.b_list.Add(new B(a) { name = "b1" });
            a.b_list.Add(new B(a) { name = "b2" });

            A a2 = (A)a.DeepClone();
            a2.name = "second_A";

            // Perform re-parenting manually after deep copy.
            foreach( var b in a2.b_list )
                b.parent = a2;


            Debug.WriteLine("ok");

        }
    }

    public class A
    {
        public String name = "one";
        public List<String> list = new List<string>();
        public List<String> null_list;
        public List<B> b_list = new List<B>();
        private int private_pleaseCopyMeAsWell = 5;

        public override string ToString()
        {
            return "A(" + name + ")";
        }
    }

    public class B
    {
        public B() { }
        public B(A _parent) { parent = _parent; }
        public A parent;
        public String name = "two";
    }


    public static class ReflectionEx
    {
        public static Type GetUnderlyingType(this MemberInfo member)
        {
            Type type;
            switch (member.MemberType)
            {
                case MemberTypes.Field:
                    type = ((FieldInfo)member).FieldType;
                    break;
                case MemberTypes.Property:
                    type = ((PropertyInfo)member).PropertyType;
                    break;
                case MemberTypes.Event:
                    type = ((EventInfo)member).EventHandlerType;
                    break;
                default:
                    throw new ArgumentException("member must be if type FieldInfo, PropertyInfo or EventInfo", "member");
            }
            return Nullable.GetUnderlyingType(type) ?? type;
        }

        /// <summary>
        /// Gets fields and properties into one array.
        /// Order of properties / fields will be preserved in order of appearance in class / struct. (MetadataToken is used for sorting such cases)
        /// </summary>
        /// <param name="type">Type from which to get</param>
        /// <returns>array of fields and properties</returns>
        public static MemberInfo[] GetFieldsAndProperties(this Type type)
        {
            List<MemberInfo> fps = new List<MemberInfo>();
            fps.AddRange(type.GetFields());
            fps.AddRange(type.GetProperties());
            fps = fps.OrderBy(x => x.MetadataToken).ToList();
            return fps.ToArray();
        }

        public static object GetValue(this MemberInfo member, object target)
        {
            if (member is PropertyInfo)
            {
                return (member as PropertyInfo).GetValue(target, null);
            }
            else if (member is FieldInfo)
            {
                return (member as FieldInfo).GetValue(target);
            }
            else
            {
                throw new Exception("member must be either PropertyInfo or FieldInfo");
            }
        }

        public static void SetValue(this MemberInfo member, object target, object value)
        {
            if (member is PropertyInfo)
            {
                (member as PropertyInfo).SetValue(target, value, null);
            }
            else if (member is FieldInfo)
            {
                (member as FieldInfo).SetValue(target, value);
            }
            else
            {
                throw new Exception("destinationMember must be either PropertyInfo or FieldInfo");
            }
        }

        /// <summary>
        /// Deep clones specific object.
        /// Analogue can be found here: https://mcmap.net/q/9314/-how-do-you-do-a-deep-copy-of-an-object-in-net-duplicate
        /// This is now improved version (list support added)
        /// </summary>
        /// <param name="obj">object to be cloned</param>
        /// <returns>full copy of object.</returns>
        public static object DeepClone(this object obj)
        {
            if (obj == null)
                return null;

            Type type = obj.GetType();

            if (obj is IList)
            {
                IList list = ((IList)obj);
                IList newlist = (IList)Activator.CreateInstance(obj.GetType(), list.Count);

                foreach (object elem in list)
                    newlist.Add(DeepClone(elem));

                return newlist;
            } //if

            if (type.IsValueType || type == typeof(string))
            {
                return obj;
            }
            else if (type.IsArray)
            {
                Type elementType = Type.GetType(type.FullName.Replace("[]", string.Empty));
                var array = obj as Array;
                Array copied = Array.CreateInstance(elementType, array.Length);

                for (int i = 0; i < array.Length; i++)
                    copied.SetValue(DeepClone(array.GetValue(i)), i);

                return Convert.ChangeType(copied, obj.GetType());
            }
            else if (type.IsClass)
            {
                object toret = Activator.CreateInstance(obj.GetType());

                MemberInfo[] fields = type.GetFieldsAndProperties();
                foreach (MemberInfo field in fields)
                {
                    // Don't clone parent back-reference classes. (Using special kind of naming 'parent' 
                    // to indicate child's parent class.
                    if (field.Name == "parent")
                    {
                        continue;
                    }

                    object fieldValue = field.GetValue(obj);

                    if (fieldValue == null)
                        continue;

                    field.SetValue(toret, DeepClone(fieldValue));
                }

                return toret;
            }
            else
            {
                // Don't know that type, don't know how to clone it.
                if (Debugger.IsAttached)
                    Debugger.Break();

                return null;
            }
        } //DeepClone
    }

}
Iconoclast answered 24/4, 2015 at 19:39 Comment(0)
W
2

Yet another JSON.NET answer. This version works with classes that don't implement ISerializable.

public static class Cloner
{
    public static T Clone<T>(T source)
    {
        if (ReferenceEquals(source, null))
            return default(T);

        var settings = new JsonSerializerSettings { ContractResolver = new ContractResolver() };

        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source, settings), settings);
    }

    class ContractResolver : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                .Select(p => base.CreateProperty(p, memberSerialization))
                .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                    .Select(f => base.CreateProperty(f, memberSerialization)))
                .ToList();
            props.ForEach(p => { p.Writable = true; p.Readable = true; });
            return props;
        }
    }
}
Weedy answered 14/3, 2018 at 11:37 Comment(0)
R
2

The generic approaches are all technically valid, but I just wanted to add a note from myself since we rarely actually need a real deep copy, and I would strongly oppose using generic deep copying in actual business applications since that makes it so you might have many places where the objects are copied and then modified explicitly, its easy to get lost.

In most real-life situations also you want to have as much granular control over the copying process as possible since you are not only coupled to the data access framework but also in practice the copied business objects should rarely be 100% the same. Think an example referenceId's used by the ORM to identify object references, a full deep copy will also copy this id's so while in-memory the objects will be different, as soon as you submit it to the datastore, it will complain, so you will have to modify this properties manually after copying anyway and if the object changes you need to adjust it in all of the places which use the generic deep copying.

Expanding on @cregox answer with ICloneable, what actually is a deep copy? Its just a newly allocated object on the heap that is identical to the original object but occupies a different memory space, as such rather than using a generic cloner functionality why not just create a new object?

I personally use the idea of static factory methods on my domain objects.

Example:

    public class Client
    {
        public string Name { get; set; }

        protected Client()
        {
        }

        public static Client Clone(Client copiedClient)
        {
            return new Client
            {
                Name = copiedClient.Name
            };
        }
    }

    public class Shop
    {
        public string Name { get; set; }

        public string Address { get; set; }

        public ICollection<Client> Clients { get; set; }

        public static Shop Clone(Shop copiedShop, string newAddress, ICollection<Client> clients)
        {
            var copiedClients = new List<Client>();
            foreach (var client in copiedShop.Clients)
            {
                copiedClients.Add(Client.Clone(client));
            }

            return new Shop
            {
                Name = copiedShop.Name,
                Address = newAddress,
                Clients = copiedClients
            };
        }
    }

If someone is looking how he can structure object instantiation while retaining full control over the copying process that's a solution that I have been personally very successful with. The protected constructors also make it so, other developers are forced to use the factory methods which gives a neat single point of object instantiation encapsulating the construction logic inside of the object. You can also overload the method and have several clone logic's for different places if necessary.

Romonaromonda answered 12/10, 2018 at 12:59 Comment(0)
S
2

Deep cloning is about copying state. For .net state means fields.

Let's say one have an hierarchy:

static class RandomHelper
{
    private static readonly Random random = new Random();

    public static int Next(int maxValue) => random.Next(maxValue);
}

class A
{
    private readonly int random = RandomHelper.Next(100);

    public override string ToString() => $"{typeof(A).Name}.{nameof(random)} = {random}";
}

class B : A
{
    private readonly int random = RandomHelper.Next(100);

    public override string ToString() => $"{typeof(B).Name}.{nameof(random)} = {random} {base.ToString()}";
}

class C : B
{
    private readonly int random = RandomHelper.Next(100);

    public override string ToString() => $"{typeof(C).Name}.{nameof(random)} = {random} {base.ToString()}";
}

Cloning can be done:

static class DeepCloneExtension
{
    // consider instance fields, both public and non-public
    private static readonly BindingFlags bindingFlags =
        BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

    public static T DeepClone<T>(this T obj) where T : new()
    {
        var type = obj.GetType();
        var result = (T)Activator.CreateInstance(type);

        do
            // copy all fields
            foreach (var field in type.GetFields(bindingFlags))
                field.SetValue(result, field.GetValue(obj));
        // for every level of hierarchy
        while ((type = type.BaseType) != typeof(object));

        return result;
    }
}

Demo1:

Console.WriteLine(new C());
Console.WriteLine(new C());

var c = new C();
Console.WriteLine($"{Environment.NewLine}Image: {c}{Environment.NewLine}");

Console.WriteLine(new C());
Console.WriteLine(new C());

Console.WriteLine($"{Environment.NewLine}Clone: {c.DeepClone()}{Environment.NewLine}");

Console.WriteLine(new C());
Console.WriteLine(new C());

Result:

C.random = 92 B.random = 66 A.random = 71
C.random = 36 B.random = 64 A.random = 17

Image: C.random = 96 B.random = 18 A.random = 46

C.random = 60 B.random = 7 A.random = 37
C.random = 78 B.random = 11 A.random = 18

Clone: C.random = 96 B.random = 18 A.random = 46

C.random = 33 B.random = 63 A.random = 38
C.random = 4 B.random = 5 A.random = 79

Notice, all new objects have random values for random field, but clone exactly matches the image

Demo2:

class D
{
    public event EventHandler Event;
    public void RaiseEvent() => Event?.Invoke(this, EventArgs.Empty);
}

// ...

var image = new D();
Console.WriteLine($"Created obj #{image.GetHashCode()}");

image.Event += (sender, e) => Console.WriteLine($"Event from obj #{sender.GetHashCode()}");
Console.WriteLine($"Subscribed to event of obj #{image.GetHashCode()}");

image.RaiseEvent();
image.RaiseEvent();

var clone = image.DeepClone();
Console.WriteLine($"obj #{image.GetHashCode()} cloned to obj #{clone.GetHashCode()}");

clone.RaiseEvent();
image.RaiseEvent();

Result:

Created obj #46104728
Subscribed to event of obj #46104728
Event from obj #46104728
Event from obj #46104728
obj #46104728 cloned to obj #12289376
Event from obj #12289376
Event from obj #46104728

Notice, event backing field is copied too and client is subscribed to clone's event too.

Sundowner answered 20/6, 2019 at 17:27 Comment(1)
It really is. It can cause tricky side-effects, so it should be use carefully.Sundowner
P
1

This will copy all readable and writable properties of an object to another.

 public class PropertyCopy<TSource, TTarget> 
                        where TSource: class, new()
                        where TTarget: class, new()
        {
            public static TTarget Copy(TSource src, TTarget trg, params string[] properties)
            {
                if (src==null) return trg;
                if (trg == null) trg = new TTarget();
                var fulllist = src.GetType().GetProperties().Where(c => c.CanWrite && c.CanRead).ToList();
                if (properties != null && properties.Count() > 0)
                    fulllist = fulllist.Where(c => properties.Contains(c.Name)).ToList();
                if (fulllist == null || fulllist.Count() == 0) return trg;

                fulllist.ForEach(c =>
                    {
                        c.SetValue(trg, c.GetValue(src));
                    });

                return trg;
            }
        }

and this is how you use it:

 var cloned = Utils.PropertyCopy<TKTicket, TKTicket>.Copy(_tmp, dbsave,
                                                            "Creation",
                                                            "Description",
                                                            "IdTicketStatus",
                                                            "IdUserCreated",
                                                            "IdUserInCharge",
                                                            "IdUserRequested",
                                                            "IsUniqueTicketGenerated",
                                                            "LastEdit",
                                                            "Subject",
                                                            "UniqeTicketRequestId",
                                                            "Visibility");

or to copy everything:

var cloned = Utils.PropertyCopy<TKTicket, TKTicket>.Copy(_tmp, dbsave);
Pineapple answered 17/9, 2008 at 0:6 Comment(0)
H
1

how about just recasting inside a method that should invoke basically a automatic copy constructor

T t = new T();
T t2 = (T)t;  //eh something like that

        List<myclass> cloneum;
        public void SomeFuncB(ref List<myclass> _mylist)
        {
            cloneum = new List<myclass>();
            cloneum = (List < myclass >) _mylist;
            cloneum.Add(new myclass(3));
            _mylist = new List<myclass>();
        }

seems to work to me

Hilten answered 13/4, 2014 at 12:53 Comment(1)
Tried recasting with an object with properties with simple types and reference types. Only did a shallow copy of the property that was a reference type.Weathertight
B
1

When using Marc Gravells protobuf-net as your serializer the accepted answer needs some slight modifications, as the object to copy won't be attributed with [Serializable] and, therefore, isn't serializable and the Clone-method will throw an exception.
I modified it to work with protobuf-net:

public static T Clone<T>(this T source)
{
    if(Attribute.GetCustomAttribute(typeof(T), typeof(ProtoBuf.ProtoContractAttribute))
           == null)
    {
        throw new ArgumentException("Type has no ProtoContract!", "source");
    }

    if(Object.ReferenceEquals(source, null))
    {
        return default(T);
    }

    IFormatter formatter = ProtoBuf.Serializer.CreateFormatter<T>();
    using (Stream stream = new MemoryStream())
    {
        formatter.Serialize(stream, source);
        stream.Seek(0, SeekOrigin.Begin);
        return (T)formatter.Deserialize(stream);
    }
}

This checks for the presence of a [ProtoContract] attribute and uses protobufs own formatter to serialize the object.

Brougham answered 22/8, 2015 at 11:36 Comment(0)
P
1

I found a new way to do it that is Emit.

We can use Emit to add the IL to app and run it. But I dont think its a good way for I want to perfect this that I write my answer.

The Emit can see the official document and Guide

You should learn some IL to read the code. I will write the code that can copy the property in class.

public static class Clone
{        
    // ReSharper disable once InconsistentNaming
    public static void CloneObjectWithIL<T>(T source, T los)
    {
        //see http://lindexi.oschina.io/lindexi/post/C-%E4%BD%BF%E7%94%A8Emit%E6%B7%B1%E5%85%8B%E9%9A%86/
        if (CachedIl.ContainsKey(typeof(T)))
        {
            ((Action<T, T>) CachedIl[typeof(T)])(source, los);
            return;
        }
        var dynamicMethod = new DynamicMethod("Clone", null, new[] { typeof(T), typeof(T) });
        ILGenerator generator = dynamicMethod.GetILGenerator();

        foreach (var temp in typeof(T).GetProperties().Where(temp => temp.CanRead && temp.CanWrite))
        {
            //do not copy static that will except
            if (temp.GetAccessors(true)[0].IsStatic)
            {
                continue;
            }

            generator.Emit(OpCodes.Ldarg_1);// los
            generator.Emit(OpCodes.Ldarg_0);// s
            generator.Emit(OpCodes.Callvirt, temp.GetMethod);
            generator.Emit(OpCodes.Callvirt, temp.SetMethod);
        }
        generator.Emit(OpCodes.Ret);
        var clone = (Action<T, T>) dynamicMethod.CreateDelegate(typeof(Action<T, T>));
        CachedIl[typeof(T)] = clone;
        clone(source, los);
    }

    private static Dictionary<Type, Delegate> CachedIl { set; get; } = new Dictionary<Type, Delegate>();
}

The code can be deep copy but it can copy the property. If you want to make it to deep copy that you can change it for the IL is too hard that I cant do it.

Predestine answered 8/8, 2017 at 0:44 Comment(0)
T
1

C# Extension that'll support for "not ISerializable" types too.

 public static class AppExtensions
 {                                                                      
       public static T DeepClone<T>(this T a)
       {
           using (var stream = new MemoryStream())
           {
               var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));

               serializer.Serialize(stream, a);
               stream.Position = 0;
               return (T)serializer.Deserialize(stream);
           }
       }                                                                    
 }

Usage

       var obj2 = obj1.DeepClone()
Thermopylae answered 3/5, 2018 at 8:18 Comment(0)
K
1

Using System.Text.Json:

https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/

public static T DeepCopy<T>(this T source)
{
    return source == null ? default : JsonSerializer.Parse<T>(JsonSerializer.ToString(source));
}

The new API is using Span<T>. This should be fast, would be nice to do some benchmarks.

Note: there's no need for ObjectCreationHandling.Replace like in Json.NET as it will replace collection values by default. You should forget about Json.NET now as everything is going to be replaced with the new official API.

I'm not sure this will work with private fields.

Klystron answered 28/6, 2019 at 11:19 Comment(0)
A
1

An addition to @Konrad and @craastad with using built in System.Text.Json for .NET >5

https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-5-0

Method:

public static T Clone<T>(T source)
{
    var serialized = JsonSerializer.Serialize(source);
    return JsonSerializer.Deserialize<T>(serialized);
}

Extension method:

public static class SystemExtension
{
    public static T Clone<T>(this T source)
    {
        var serialized = JsonSerializer.Serialize(source);
        return JsonSerializer.Deserialize<T>(serialized);
    }
}
Associative answered 8/3, 2021 at 22:32 Comment(1)
If you vote down please add a comment why, hard to improve answers otherwise.Associative
A
1

using System.Text.Json;

public static class CloneExtensions
{
    public static T Clone<T>(this T cloneable) where T : new()
    {
        var toJson = JsonSerializer.Serialize(cloneable);
        return JsonSerializer.Deserialize<T>(toJson);
    }
}
Aphaeresis answered 5/5, 2021 at 14:9 Comment(0)
F
1

I did some benchmark on current answers and found some interesting facts.

Using BinarySerializer => https://mcmap.net/q/9283/-deep-cloning-objects

Using XmlSerializer => https://mcmap.net/q/9283/-deep-cloning-objects

Using Activator.CreateInstance => https://mcmap.net/q/9283/-deep-cloning-objects

These are the results

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.18363.1734 (1909/November2019Update/19H2)

Intel Core i5-6200U CPU 2.30GHz (Skylake), 1 CPU, 4 logical and 2 physical cores [Host] : .NET Framework 4.8 (4.8.4400.0), X86 LegacyJIT DefaultJob : .NET Framework 4.8 (4.8.4400.0), X86 LegacyJIT

Method Mean Error StdDev Gen 0 Allocated
BinarySerializer 220.69 us 4.374 us 9.963 us 49.8047 77 KB
XmlSerializer 182.72 us 3.619 us 9.405 us 21.9727 34 KB
Activator.CreateInstance 49.99 us 0.992 us 2.861 us 1.9531 3 KB
Ftlb answered 16/9, 2021 at 15:31 Comment(0)
S
1

Building upon @craastad's answer, for derived classes.

In the original answer, if the caller is calling DeepCopy on a base class object, the cloned object is of a base class. But the following code will return the derived class.

using Newtonsoft.Json;

public static T DeepCopy<T>(this T source)
{
    return (T)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source), source.GetType());
}
Seacock answered 3/8, 2022 at 23:7 Comment(0)
A
0

For the cloning process, the object can be converted to the byte array first and then converted back to the object.

public static class Extentions
{
    public static T Clone<T>(this T obj)
    {
        byte[] buffer = BinarySerialize(obj);
        return (T)BinaryDeserialize(buffer);
    }

    public static byte[] BinarySerialize(object obj)
    {
        using (var stream = new MemoryStream())
        {
            var formatter = new BinaryFormatter(); 
            formatter.Serialize(stream, obj); 
            return stream.ToArray();
        }
    }

    public static object BinaryDeserialize(byte[] buffer)
    {
        using (var stream = new MemoryStream(buffer))
        {
           var formatter = new BinaryFormatter(); 
           return formatter.Deserialize(stream);
        }
    }
}

The object must be serialized for the serialization process.

[Serializable]
public class MyObject
{
    public string Name  { get; set; }
}

Usage:

MyObject myObj  = GetMyObj();
MyObject newObj = myObj.Clone();
Ahwaz answered 23/5, 2020 at 17:48 Comment(0)
D
0

This is a way to perfeclty clone also with anonymous or object instance

   public static T CloneJson<T>(T source)
{
    if (ReferenceEquals(source, null))
    {
        return default;
    }

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
}

private object Clone(object instance)
{
    Type type = instance.GetType();
    MethodInfo genericMethod = this.GetType().GetMethod(nameof(CloneJson));
    MethodInfo cloneMethod = genericMethod.MakeGenericMethod(type);
    object clone = cloneMethod.Invoke(null, new object[] { instance });
    return clone;
}
Disprove answered 26/6, 2023 at 10:32 Comment(0)
S
-1

Found this package, who seems quicker of DeepCloner, and with no dependencies, compared to it.

https://github.com/AlenToma/FastDeepCloner

Signorina answered 6/10, 2021 at 19:37 Comment(0)
V
-1

If you use net.core and the object is serializable, you can use

var jsonBin = BinaryData.FromObjectAsJson(yourObject);

then

var yourObjectCloned = jsonBin.ToObjectFromJson<YourType>();

BinaryData is in dotnet therefore you don't need a third party lib. It also can handle the situation that the property on your class is Object type (the actual data in your property still need to be serializable)

Voussoir answered 10/8, 2022 at 5:1 Comment(0)
W
-2

I know that this question and answer sits here for a while and following is not quite answer but rather observation, to which I came across recently when I was checking whether indeed privates are not being cloned (I wouldn't be myself if I have not ;) when I happily copy-pasted @johnc updated answer.

I simply made myself extension method (which is pretty much copy-pasted form aforementioned answer):

public static class CloneThroughJsonExtension
{
    private static readonly JsonSerializerSettings DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };

    public static T CloneThroughJson<T>(this T source)
    {
        return ReferenceEquals(source, null) ? default(T) : JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), DeserializeSettings);
    }
}

and dropped naively class like this (in fact there was more of those but they are unrelated):

public class WhatTheHeck
{
    public string PrivateSet { get; private set; } // matches ctor param name

    public string GetOnly { get; } // matches ctor param name

    private readonly string _indirectField;
    public string Indirect => $"Inception of: {_indirectField} "; // matches ctor param name
    public string RealIndirectFieldVaule => _indirectField;

    public WhatTheHeck(string privateSet, string getOnly, string indirect)
    {
        PrivateSet = privateSet;
        GetOnly = getOnly;
        _indirectField = indirect;
    }
}

and code like this:

var clone = new WhatTheHeck("Private-Set-Prop cloned!", "Get-Only-Prop cloned!", "Indirect-Field clonned!").CloneThroughJson();
Console.WriteLine($"1. {clone.PrivateSet}");
Console.WriteLine($"2. {clone.GetOnly}");
Console.WriteLine($"3.1. {clone.Indirect}");
Console.WriteLine($"3.2. {clone.RealIndirectFieldVaule}");

resulted in:

1. Private-Set-Prop cloned!
2. Get-Only-Prop cloned!
3.1. Inception of: Inception of: Indirect-Field cloned!
3.2. Inception of: Indirect-Field cloned!

I was whole like: WHAT THE F... so I grabbed Newtonsoft.Json Github repo and started to dig. What it comes out, is that: while deserializing a type which happens to have only one ctor and its param names match (case insensitive) public property names they will be passed to ctor as those params. Some clues can be found in the code here and here.

Bottom line

I know that it is rather not common case and example code is bit abusive, but hey! It got me by surprise when I was checking whether there is any dragon waiting in the bushes to jump out and bite me in the ass. ;)

Wordless answered 1/2, 2017 at 19:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.