By user18931


2008-09-24 19:39:39 8 Comments

I want a true deep copy. In Java, this was easy, but how do you do it in C#?

11 comments

@Contango 2011-12-30 19:05:02

You can use Nested MemberwiseClone to do a deep copy. Its almost the same speed as copying a value struct, and its an order of magnitude 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 (4.77 seconds for deep nested MemberwiseCopy vs. 39.93 seconds for Serialization). Using nested MemberwiseCopy is almost as fast as copying a struct, and copying a struct is pretty darn close to the theoretical maximum speed .NET is capable of, which is probably quite close to the speed of the same thing in C or C++ (but would have to run some equivalent benchmarks to check this claim).

    Demo 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 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 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:

// 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 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", sw.Elapsed, total);
        }
        {               
            Console.Write("Demo 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", sw.Elapsed, total);
        }
        {
            Console.Write("Demo 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.

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.
  • 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 a method which creates another copy of the original object in memory.
  • 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. It's also essential for any use case where you are modifying objects, then feeding the modified copies into a queue.

Update

It's probably possible to use reflection to recursively walk through the object graph to do a deep copy. WCF uses this technique to serialize an object, including all of its children. The trick is to annotate all of the child objects with an attribute that makes it discoverable. You might lose some performance benefits, however.

Update

Quote on independent speed test (see comments below):

I've run my own speed test using Neil's serialize/deserialize extension method, Contango's Nested MemberwiseClone, Alex Burtsev's reflection-based extension method and AutoMapper, 1 million times each. Serialize-deserialize was slowest, taking 15.7 seconds. Then came AutoMapper, taking 10.1 seconds. Much faster was the reflection-based method which took 2.4 seconds. By far the fastest was Nested MemberwiseClone, taking 0.1 seconds. Comes down to performance versus hassle of adding code to each class to clone it. If performance isn't an issue go with Alex Burtsev's method. – Simon Tewsi

@user420667 2012-04-01 15:33:01

Good post. Any idea why serialization is so much slower? Also, how would your checksum work? Why not just have an equality checker?

@Contango 2012-05-20 17:59:42

@user420667 The checksum works by manually converting all of the parameters within the class into ints, then adding up said ints to create a checksum. Its useful if you are feeding copies of objects into a queue in one thread, and reading out with another thread. You would have to methods: ChecksumWrite and ChecksumVerify.

@Contango 2012-05-20 18:01:34

@user420667 Could use an equality checker as well - but only if you had something else to compare it to. If you are feeding things into a queue, how do you work out if the items popping out the other end are valid or not? An equality checker will not work, whereas a checksum will verify internal consistency. Once the code has been proven to work with say 100 million items in the queue over a couple of weeks of deployment, you can be pretty sure that the code is solidly written, and you can remove the checksum.

@Neil 2012-05-23 14:37:46

I can confirm that this is much faster than the serialization method. The cost is: writing more code; the maintenance risk of adding a field without adding it to the clone method; need to write helper classes for any 3rd party classes (such as Dictionary<>)

@user420667 2012-05-23 16:51:43

@Gravitas: Ah ok. I guess I had envisioned item1 compared to item2, so it seemed excessive to do item1.GetChecksum() only to compare it to item2.GetChecksum(), which would require more operations than a simple equality comparison. But if you're only comparing it to itself at a later time..., i don't know that sounds like an impossible task. My ChecksumVerify would probably call GetChecksum(), so the two would be almost certainly guaranteed to match.

@user420667 2012-05-23 16:55:57

@Gravitas: I guess you're concerned about the integrity of the data over some sort of noisy transmission line, right?

@Alex Burtsev 2012-07-12 04:16:28

You can create an extension method that works on any object, see my answer stackoverflow.com/a/11308879/235715

@Contango 2013-01-28 19:03:57

@user420667. No, I am more concerned with cloning objects incorrectly which leads to bugs (see my second to last bullet point in my answer above).

@supercat 2013-09-23 19:53:18

It's too bad neither Java nor .NET distinguishes among references that encapsulate identity, mutable state, both, or neither. Conceptually, there should only be one type of "clone": a new object where each reference encapsulates the same thing as in the corresponding reference in the original. If a reference encapsulates identity, the clone's reference must refer to the same object. If it encapsulates mutable state but not identity, the clone must receive a reference to a different object with the same state [otherwise both references would erroneously...

@supercat 2013-09-23 20:01:00

...encapsulate identity as well as state]. An object reference that encapsulates both identity and state cannot be cloned except by copying everything else which holds a reference to that object--a feat which is often difficult or impossible. While references to some types of object will usually be used to encapsulate identity, and references to others will usually encapsulate mutable state, knowing the type of an object is not sufficient to the purpose for which a reference is held.

@Simon Tewsi 2016-06-07 15:12:55

I've run my own speed test using Neil's serialize/deserialize extension method, Contango's Nested MemberwiseClone, Alex Burtsev's reflection-based extension method and AutoMapper, 1 million times each. Serialize-deserialize was slowest, taking 15.7 seconds. Then came AutoMapper, taking 10.1 seconds. Much faster was the reflection-based method which took 2.4 seconds. By far the fastest was Nested MemberwiseClone, taking 0.1 seconds. Comes down to performance versus hassle of adding code to each class to clone it. If performance isn't an issue go with Alex Burtsev's method.

@Alex Burtsev 2012-07-03 10:20:18

I wrote a deep object copy extension method, based on recursive "MemberwiseClone". It is fast (three times faster than BinaryFormatter), and it works with any object. You don't need a default constructor or serializable attributes.

Source code:

using System.Collections.Generic;
using System.Reflection;
using System.ArrayExtensions;

namespace System
{
    public static class ObjectExtensions
    {
        private static readonly MethodInfo CloneMethod = typeof(Object).GetMethod("MemberwiseClone", BindingFlags.NonPublic | BindingFlags.Instance);

        public static bool IsPrimitive(this Type type)
        {
            if (type == typeof(String)) return true;
            return (type.IsValueType & type.IsPrimitive);
        }

        public static Object Copy(this Object originalObject)
        {
            return InternalCopy(originalObject, new Dictionary<Object, Object>(new ReferenceEqualityComparer()));
        }
        private static Object InternalCopy(Object originalObject, IDictionary<Object, Object> visited)
        {
            if (originalObject == null) return null;
            var typeToReflect = originalObject.GetType();
            if (IsPrimitive(typeToReflect)) return originalObject;
            if (visited.ContainsKey(originalObject)) return visited[originalObject];
            if (typeof(Delegate).IsAssignableFrom(typeToReflect)) return null;
            var cloneObject = CloneMethod.Invoke(originalObject, null);
            if (typeToReflect.IsArray)
            {
                var arrayType = typeToReflect.GetElementType();
                if (IsPrimitive(arrayType) == false)
                {
                    Array clonedArray = (Array)cloneObject;
                    clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices));
                }

            }
            visited.Add(originalObject, cloneObject);
            CopyFields(originalObject, visited, cloneObject, typeToReflect);
            RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect);
            return cloneObject;
        }

        private static void RecursiveCopyBaseTypePrivateFields(object originalObject, IDictionary<object, object> visited, object cloneObject, Type typeToReflect)
        {
            if (typeToReflect.BaseType != null)
            {
                RecursiveCopyBaseTypePrivateFields(originalObject, visited, cloneObject, typeToReflect.BaseType);
                CopyFields(originalObject, visited, cloneObject, typeToReflect.BaseType, BindingFlags.Instance | BindingFlags.NonPublic, info => info.IsPrivate);
            }
        }

        private static void CopyFields(object originalObject, IDictionary<object, object> visited, object cloneObject, Type typeToReflect, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy, Func<FieldInfo, bool> filter = null)
        {
            foreach (FieldInfo fieldInfo in typeToReflect.GetFields(bindingFlags))
            {
                if (filter != null && filter(fieldInfo) == false) continue;
                if (IsPrimitive(fieldInfo.FieldType)) continue;
                var originalFieldValue = fieldInfo.GetValue(originalObject);
                var clonedFieldValue = InternalCopy(originalFieldValue, visited);
                fieldInfo.SetValue(cloneObject, clonedFieldValue);
            }
        }
        public static T Copy<T>(this T original)
        {
            return (T)Copy((Object)original);
        }
    }

    public class ReferenceEqualityComparer : EqualityComparer<Object>
    {
        public override bool Equals(object x, object y)
        {
            return ReferenceEquals(x, y);
        }
        public override int GetHashCode(object obj)
        {
            if (obj == null) return 0;
            return obj.GetHashCode();
        }
    }

    namespace ArrayExtensions
    {
        public static class ArrayExtensions
        {
            public static void ForEach(this Array array, Action<Array, int[]> action)
            {
                if (array.LongLength == 0) return;
                ArrayTraverse walker = new ArrayTraverse(array);
                do action(array, walker.Position);
                while (walker.Step());
            }
        }

        internal class ArrayTraverse
        {
            public int[] Position;
            private int[] maxLengths;

            public ArrayTraverse(Array array)
            {
                maxLengths = new int[array.Rank];
                for (int i = 0; i < array.Rank; ++i)
                {
                    maxLengths[i] = array.GetLength(i) - 1;
                }
                Position = new int[array.Rank];
            }

            public bool Step()
            {
                for (int i = 0; i < Position.Length; ++i)
                {
                    if (Position[i] < maxLengths[i])
                    {
                        Position[i]++;
                        for (int j = 0; j < i; j++)
                        {
                            Position[j] = 0;
                        }
                        return true;
                    }
                }
                return false;
            }
        }
    }

}

@theJerm 2013-02-18 07:05:47

I tried this, but got an error saying I needed to have serializable attributes in my class I am cloning...

@Alex Burtsev 2013-02-18 13:42:16

@theJerm I think you have called Clone, instead of Copy, there is a Clone method that uses BinaryFormatter as described in accepted answer for benchmark comparisson

@theJerm 2013-02-19 20:23:29

Thanks Alex, yes I needed to call copy instead and that worked!

@Matt Smith 2014-04-23 16:46:26

For ReferenceEqualityComparer.GetHashCode(object obj) you should be using RuntimeHelpers.GetHashCode(obj), otherwise it will be using the objects real hashcode. See stackoverflow.com/a/11240110/495262

@Matt Smith 2014-04-23 16:51:14

Regarding IsPrimitive: what is the reason you return true for a string. Also, is there any reason you use the single & rather than && in the statement: return (type.IsValueType & type.IsPrimitive);?

@Matt Smith 2014-04-23 16:54:23

Based on reading the code, I assume this doesn't work for types containing Delegates. Do you know if the other approaches do/don't work with Delegates as well? I would assume they do not.

@Alex Burtsev 2014-04-23 18:33:23

@MattSmith You are absolutely right about GetHashCode, checked it, yep StackOverflow exception - gist.github.com/Burtsev-Alexey/11227277

@Alex Burtsev 2014-04-23 18:39:13

@MattSmith It was working for delegates, but I intently disabled it (by setting null), see github.com/Burtsev-Alexey/net-object-deep-copy/issues/7, the subscribers were cloned, in the end if you had two object A and B connected (by event subscription) you would get objects A' and B' connected, this is correct but that's not what most people want when the clone objects.

@Matt Smith 2014-04-23 18:43:28

@AlexBurtsev, Regarding the delegates--okay, I changed it to not copy delegates, but copy the reference (similar to how you treat strings), since (like strings) delegates are immutable. The serialization approach does handle delegates, but I'm not sure if they have a similar problem to what you experienced with delegates.

@Alex Burtsev 2014-04-23 18:45:34

@MattSmith Strings are treated as primitives because 1: they are immutable, 2: calling protected MemberwiseClone on string will result in memory corruption, string data will turn into random chars, and soon .NET runtime will crash with internal error saying theer is a but in .NET :-)

@Alex Burtsev 2014-04-23 19:19:21

@MattSmith I believe you do understand that by reusing same delegate in original and cloned object they will be using the same objects which were referenced in delegate, like A has delegate which modifies B, by cloning A you would get A' which modifies the same B, if you want to have the true copy (snapshot) of object graphs (memory), then simply remove the line which sets delegate to null. You would get then A modifying B, and A' modifying B'

@Matt Smith 2014-04-23 19:23:29

@AlexBurtsev, Good points. What you want somewhat depends on what objects are being accessed within the delegate. If you're accessing objects that are being copied, then you probably want the copied delegate. If you're accessing object external to the copied object, then you probably want the delegate to not be copied. That said, I don't have a use case for delegates, so perhaps it's best to leave it as unimplemented for now (i.e. I'll throw an exception).

@Matt Smith 2014-04-23 19:43:49

BTW, When I enable Delegates for my simple test case it stackoverflows. Here's my sample object I attempt to copy: shar.es/T86JR

@Taryn East 2014-07-16 00:35:54

Clearly people like this answer but... it is a link-only answer. Perhaps you could include the relevant code here on Stack Overflow?

@Leon Lucardie 2014-10-08 12:08:58

I've forked and updated your code for compatibility with the new TypeInfo-based reflection API (used in Windows Phone and Windows Store applications, and their respective PCL profiles). github.com/Gameleon12/net-object-deep-copy/blob/master/…

@Dean 2015-01-15 04:25:42

Please add an example of how to use your extension method, it will help flesh out your answer.

@Peter 2015-04-01 09:57:10

Even faster (for me) is to use JSON.NET and serialize and then deserialize. Might not work for everyone (I'm thinking private fields and such).

@Alex141 2015-04-11 21:37:46

@AlexBurtsev, your code using namespace System.ArrayExtensions, where can I get it?

@Arunas 2015-05-15 03:24:06

@Alex141 - just encountered the same puzzlement. All the relevant code is in the referenced file, there's an ArrayExtensions namespace lower down.

@kat 2015-05-26 17:21:30

This is a very clever and powerful implementation, however you have to consider a few things before deciding whether it’s right for your data model. Memberwiseclone() is so fast because it does not invoke constructors. So if your constructors are doing heavy lifting such as event subscription, you are out of luck. It relies on copying private fields of the object, bypassing the business logic in the properties and methods. For example, I saw hashCode field being copied in a HashSet collection, even though all instances have changed.

@yu_ominae 2015-05-27 04:57:36

I'm getting a StackOverflowException when cloning objects that mutually reference each other... Anybody know of a workaround?

@Alex Burtsev 2015-05-27 09:41:22

@yu_ominae cyclic references are suported and works fine. Your problem is somewhere else. If you can share source code of the class you are trying to clone, open an issue at project website. Cccasionally I run into SO Exceptions, when cloning what is not supposed to be cloned, like .NET internal infrastructure, that might get referenced accidently, especially pointers and their reflections. As an example trying to clone NHibernate entity containing collection that is attached to session, will result in big mess, because NH collection implementing IList<T> contains DbConnection field inside.

@yu_ominae 2015-05-27 10:59:06

@AlexBurtsev I was trying to clone a collection objects mirroring objects in a different application. The access is done via com calls, so maybe I have a reference in there that is causing the thing to blow up. The .Copy() method worked fine if I set a breakpoint and inspected the list content in the watch before resuming execution. Weird. I found that calling .ToList() actually achieves what I want for now, so it's all good. Thanks for the reply :)

@David 2016-03-11 09:56:18

Is there anyway I can use this but still ensure that a certain field is only copied by reference?

@Alex Burtsev 2016-03-12 05:58:23

@David Not out the box.

@g.t.w.d 2016-12-07 16:44:42

Can you explain how this is deep vs. shallow? My understanding is that memberwiseClone is shallow, and that's what you invoke in here. Unless I am missing something.

@Deepak 2017-01-05 12:39:12

Hi Alex, Thanks for your extension. Does this also "DeepCopy" events/delegates?

@Wobbles 2017-07-13 12:31:28

Seems to have issues with type PropertyInfo. Is there any way to mark properties of this type as excluded or allowed to reference?

@dannyhut 2018-12-23 06:35:20

Not a single Comment in the whole thing. WOW.

@judehall 2019-03-18 21:50:19

Still able to mutate nested lists :(

@TakeMeAsAGuest 2019-03-24 18:31:53

you dont copy arrays if its primitive+string, but one can modify one copy then other copy sees that change which is not deep copy meant to be.

@Darek 2019-03-27 15:47:55

Warning: this approach brakes XDocuments. I can no longer access attributes by name, even thou there is no namespace defined.

@Jakub Dropia 2019-05-15 15:42:59

It seems that List<BsonElement> is not properly reflected by fieldInfo. Out of: List<BsonElement> { BsonElement ("status=Connected"), BsonElement("lastConnectedTimeUtc=2019-05-15T10:50:40.557093‌​2Z") } it makes: BsonElement[] { BsonElement ("status=Connected"), BsonElement("lastConnectedTimeUtc=2019-05-15T10:50:40.557093‌​2Z"), BsonElement("="), BsonElement("=") }

@Kurt Richardson 2012-01-03 05:21:13

I believe that the BinaryFormatter approach is relatively slow (which came as a surprise to me!). You might be able to use ProtoBuf .NET for some objects if they meet the requirements of ProtoBuf. From the ProtoBuf Getting Started page (http://code.google.com/p/protobuf-net/wiki/GettingStarted):

Notes on types supported:

Custom classes that:

  • Are marked as data-contract
  • Have a parameterless constructor
  • For Silverlight: are public
  • Many common primitives, etc.
  • Single dimension arrays: T[]
  • List<T> / IList<T>
  • Dictionary<TKey, TValue> / IDictionary<TKey, TValue>
  • any type which implements IEnumerable<T> and has an Add(T) method

The code assumes that types will be mutable around the elected members. Accordingly, custom structs are not supported, since they should be immutable.

If your class meets these requirements you could try:

public static void deepCopy<T>(ref T object2Copy, ref T objectCopy)
{
    using (var stream = new MemoryStream())
    {
        Serializer.Serialize(stream, object2Copy);
        stream.Position = 0;
        objectCopy = Serializer.Deserialize<T>(stream);
    }
}

Which is VERY fast indeed...

Edit:

Here is working code for a modification of this (tested on .NET 4.6). It uses System.Xml.Serialization and System.IO. No need to mark classes as serializable.

public void DeepCopy<T>(ref T object2Copy, ref T objectCopy)
{
    using (var stream = new MemoryStream())
    {
        var serializer = new XS.XmlSerializer(typeof(T));

        serializer.Serialize(stream, object2Copy);
        stream.Position = 0;
        objectCopy = (T)serializer.Deserialize(stream);
    }
}

@Contango 2013-09-24 20:15:05

Wonder how fast it is compared to the Nested MemberwiseClone answer above?

@Basil 2011-07-04 13:57:26

    public static object CopyObject(object input)
    {
        if (input != null)
        {
            object result = Activator.CreateInstance(input.GetType());
            foreach (FieldInfo field in input.GetType().GetFields(Consts.AppConsts.FullBindingList))
            {
                if (field.FieldType.GetInterface("IList", false) == null)
                {
                    field.SetValue(result, field.GetValue(input));
                }
                else
                {
                    IList listObject = (IList)field.GetValue(result);
                    if (listObject != null)
                    {
                        foreach (object item in ((IList)field.GetValue(input)))
                        {
                            listObject.Add(CopyObject(item));
                        }
                    }
                }
            }
            return result;
        }
        else
        {
            return null;
        }
    }

This way is a few times faster than BinarySerialization AND this does not require the [Serializable] attribute.

@Rob McCready 2011-07-05 07:04:54

You're not continuing the deep copy down your non-IList branch and I think you would have issues with ICollection/IEnumerable.

@Contango 2012-01-01 23:29:52

Using the "Nested MemberwiseClone" technique is an order of magnitude faster again (see my post under @Gravitas).

@user5447154 2015-11-13 15:47:16

what are Consts ?

@Developer 2018-04-24 07:10:57

What is Consts.AppConsts.FullBindingList?

@Jordan Morris 2013-01-25 11:42:01

I have a simpler idea. Use LINQ with a new selection.

public class Fruit
{
  public string Name {get; set;}
  public int SeedCount {get; set;}
}

void SomeMethod()
{
  List<Fruit> originalFruits = new List<Fruit>();
  originalFruits.Add(new Fruit {Name="Apple", SeedCount=10});
  originalFruits.Add(new Fruit {Name="Banana", SeedCount=0});

  //Deep Copy
  List<Fruit> deepCopiedFruits = from f in originalFruits
              select new Fruit {Name=f.Name, SeedCount=f.SeedCount};
}

@Nelson Rothermel 2013-02-04 19:32:16

It's not simpler when you have mutable reference types, many properties, lists with sublists, etc. This can work in a few simple scenarios, but is still error-prone when your Fruit class adds another property and you forget to change your method.

@Tarec 2014-02-05 10:35:23

Reference assignment 'Name=f.Name' is shallow copying.

@Umar Abbas 2014-04-10 05:49:53

if we have 100 properties then our whole day will be consumed just writing such code for one object and so on...

@Arturo Torres Sánchez 2015-05-20 17:58:14

@Tarec, if Name is a string, and strings are immutable, it shouldn't matter.

@alex 2012-04-22 11:23:31

The best way is:

    public interface IDeepClonable<T> where T : class
    {
        T DeepClone();
    }

    public class MyObj : IDeepClonable<MyObj>
    {
        public MyObj Clone()
        {
            var myObj = new MyObj();
            myObj._field1 = _field1;//value type
            myObj._field2 = _field2;//value type
            myObj._field3 = _field3;//value type

            if (_child != null)
            {
                myObj._child = _child.DeepClone(); //reference type .DeepClone() that does the same
            }

            int len = _array.Length;
            myObj._array = new MyObj[len]; // array / collection
            for (int i = 0; i < len; i++)
            {
                myObj._array[i] = _array[i];
            }

            return myObj;
        }

        private bool _field1;
        public bool Field1
        {
            get { return _field1; }
            set { _field1 = value; }
        }

        private int _field2;
        public int Property2
        {
            get { return _field2; }
            set { _field2 = value; }
        }

        private string _field3;
        public string Property3
        {
            get { return _field3; }
            set { _field3 = value; }
        }

        private MyObj _child;
        private MyObj Child
        {
            get { return _child; }
            set { _child = value; }
        }

        private MyObj[] _array = new MyObj[4];
    }

@Toxantron 2016-06-09 20:50:31

Using CGbR Clone Generator you get the same result without manually writing the code.

@Neil 2009-07-31 16:51:03

Building on Kilhoffer's solution...

With C# 3.0 you can create an extension method as follows:

public static class ExtensionMethods
{
    // Deep clone
    public static T DeepClone<T>(this T a)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, a);
            stream.Position = 0;
            return (T) formatter.Deserialize(stream);
        }
    }
}

which extends any class that's been marked as [Serializable] with a DeepClone method

MyClass copy = obj.DeepClone();

@Amir Rezaei 2011-02-11 14:35:31

To that add "public static T DeepClone<T>(this T a) where T : ISerializable"

@Neil 2011-02-14 16:10:16

@Amir - it isn't necessary for the class to implement ISerializable, Marking with SerializableAttribute is sufficient. The attribute uses reflection to perform serialization, while the interface allows you to write a custom serializer

@Michael Blackburn 2011-03-30 19:47:10

I agree with your statement, but I like Amir's suggestion b/c it provides compile-time checking. Is there any way to reconcile the two?

@om471987 2012-05-06 18:17:44

Passed unit test var stringbuilder = new StringBuilder("TestData"); var copy = stringbuilder.DeepClone(); Assert.IsFalse(Equals(stringbuilder,copy)); Thanks a lot.

@Contango 2012-05-20 18:02:54

@Neil This method is 10x slower than the NestedMemberwiseClone method, see my post on this page.

@Neil 2012-05-23 13:50:41

Hi @Gravitas. It's no surprise that hand-coded methods can out-perform a solution that uses reflection. It would be interesting to compare the performance of your solution to a hand-coded serialization method (i.e. implementing ISerializable)

@Neil 2012-05-23 14:34:04

@Gravitas, hand-coded serialization was no better. Your hand-coded clone method is much faster for simple classes (maybe more like 100x)

@Mark Kram 2012-08-07 19:25:33

+1 @Neil - Thanks this is eactly what I was looking for!

@nawfal 2013-04-17 19:39:49

780 rep just for adding a this.. Power of extension methods :)

@Neil 2013-05-01 08:29:52

Hi @nawfal - well at the time there was also a bug in Kilhoffer's code that I didn't have enough karma to fix. But yes - my best contribution so far really is this trivial

@David 2015-08-05 09:55:49

this trivial. no pun intended heheheh

@Brad Oestreicher 2019-02-14 15:44:47

I wrote a DeepClone method based on Neil's answer. It worked great, until I called DeepClone on an object whose class was defined in a 'plug-in' ... an assembly that I loaded programmatically. That caused a SerializationException to be thrown with an error of 'Unable to find assembly xxx'. I solved that problem with a solution I posted here

@Eugene 2013-02-13 13:50:01

The MSDN documentation seems to hint that Clone should perform a deep copy, but it is never explicitly stated:

The ICloneable interface contains one member, Clone, which is intended to support cloning beyond that supplied by MemberWiseClone… The MemberwiseClone method creates a shallow copy…

You can find my post helpful.

http://pragmaticcoding.com/index.php/cloning-objects-in-c/

@Mahmoud Samy 2016-08-08 18:54:30

The problem with ICloneable is that the Clone method does not explicitly specify whether it is performing a shallow or deep copy, so callers can never be sure. Hence, there is some [discussion|blogs.msdn.com/brada/archive/2004/05/03/125427.a‌​spx] about making ICloneable obsolete in the .NET Framework.

@Kilhoffer 2008-09-24 19:40:42

I've seen a few different approaches to this, but I use a generic utility method as such:

public static T DeepClone<T>(T obj)
{
 using (var ms = new MemoryStream())
 {
   var formatter = new BinaryFormatter();
   formatter.Serialize(ms, obj);
   ms.Position = 0;

   return (T) formatter.Deserialize(ms);
 }
}

Notes:

  • Your class MUST be marked as [Serializable] in order for this to work.
  • Your source file must include the following code:

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

@Patrick Desjardins 2008-09-24 19:56:05

What happen if the object have event, Do they lost everything because of the serialization?

@Ilya Ryzhenkov 2008-09-24 20:16:54

Event subscribes are included into serialization graph, since BinaryFormatter uses fields via reflection, and events are just fields of delegate types plus add/remove/invoke methods. You can use [field: NonSerialized] on event to avoid this.

@HardCode 2009-03-19 20:41:12

What is that undeclared "stream" variable? Or is it something just in C# and not VB.NET? I converted everything but that variable.

@dr. evil 2009-03-29 21:08:24

ms.Location or ms.Position? or is this something to do with the Framework version?

@Saeid Yazdani 2011-04-11 10:22:29

How to mark something as [Serializable] ??

@Dan Atkinson 2011-08-03 22:51:05

@Sean87: above the class declaration, add [Serializable]. so [Serializable]public class Foo { } will make Foo marked as serializable.

@Alex Burtsev 2012-07-12 04:19:45

Recursive MemberwiseClone will do deep copy too, it works 3 times faster then BinaryFormatter, doesn't require default constructor or any attributes. See my answer: stackoverflow.com/a/11308879/235715

@v.oddou 2013-05-21 03:13:04

This is creating a curious exception "assembly not found" while using this Utility code within the UserControlTestContainer. Its really weird because the assembly is loaded...

@KyleMit 2013-07-16 16:08:19

To address your first note programmatically, you can handle the exception a little better by using the following: if (!typeof(T).IsSerializable) { throw new ArgumentException("Type {0} is not serializable",typeof(T).Name); }

@Code Jockey 2014-03-06 19:27:15

@Chris Ward 2014-11-27 08:06:05

It's more helpful to use var formatter = new BinaryFormatter {Context = new StreamingContext(StreamingContextStates.Clone)};

@Bogdan 2015-04-25 02:17:39

while this is working in some scenarios - it seem like an overkill to serialize everything and deserialize everything just to create a copy of an object. I feel like this should be a example on how to do when you have to finish your project in the next 5 minutes.

@Toxantron 2016-06-09 20:48:34

It is also extremly slow.

@F.H. 2016-11-09 13:56:14

For those who wonder, see this easy solution: stackoverflow.com/questions/222598/…

@GDS 2017-02-06 03:47:20

ms.Position = 0 saved the day for me! Without it really weird stuff was happening.

@RiA 2018-07-18 12:54:09

Beautiful! It was right under my nose and I never even noticed it!

@Maksym Labutin 2018-10-31 14:53:44

Thank u for your answer. It works for me!

@Suresh Kumar Veluswamy 2012-04-01 03:59:40

You can try this

    public static object DeepCopy(object obj)
    {
        if (obj == null)
            return null;
        Type type = obj.GetType();

        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(DeepCopy(array.GetValue(i)), i);
            }
            return Convert.ChangeType(copied, obj.GetType());
        }
        else if (type.IsClass)
        {

            object toret = Activator.CreateInstance(obj.GetType());
            FieldInfo[] fields = type.GetFields(BindingFlags.Public |
                        BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (FieldInfo field in fields)
            {
                object fieldValue = field.GetValue(obj);
                if (fieldValue == null)
                    continue;
                field.SetValue(toret, DeepCopy(fieldValue));
            }
            return toret;
        }
        else
            throw new ArgumentException("Unknown type");
    }

Thanks to DetoX83 article on code project.

@Cyrus 2014-08-23 12:50:45

It works only if your obj has default constructor!

@David Thornley 2010-12-01 03:00:40

Maybe you only need a shallow copy, in that case use Object.MemberWiseClone().

There are good recommendations in the documentation for MemberWiseClone() for strategies to deep copy: -

http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx

@Levitikon 2011-09-26 17:38:06

Good try, but he specifically asked for a deep clone.

@Contango 2011-12-30 19:22:05

You can do a deep clone with MemberwiseClone, all you do is add nesting. See answer from @Gravitas above.

Related Questions

Sponsored Content

71 Answered Questions

[SOLVED] What is the most efficient way to deep clone an object in JavaScript?

62 Answered Questions

[SOLVED] How do I correctly clone a JavaScript object?

15 Answered Questions

[SOLVED] How to clone or copy a list?

27 Answered Questions

[SOLVED] How do I enumerate an enum in C#?

8 Answered Questions

[SOLVED] How to loop through all enum values in C#?

24 Answered Questions

[SOLVED] Cast int to enum in C#

  • 2008-08-27 03:58:21
  • lomaxx
  • 1171872 View
  • 2845 Score
  • 24 Answer
  • Tags:   c# enums casting

23 Answered Questions

[SOLVED] How do you give a C# Auto-Property a default value?

42 Answered Questions

[SOLVED] How to create Excel (.XLS and .XLSX) file in C# without installing Ms Office?

  • 2008-09-29 22:30:28
  • mistrmark
  • 996922 View
  • 1729 Score
  • 42 Answer
  • Tags:   c# .net excel file-io

38 Answered Questions

41 Answered Questions

[SOLVED] Deep cloning objects

  • 2008-09-17 00:06:27
  • NakedBrunch
  • 739467 View
  • 2031 Score
  • 41 Answer
  • Tags:   c# .net clone

Sponsored Content