How to perform a Deep Copy / Deep Clone of an object in ASP.NET C#

Classe ASP.NET C# per il controllo e il calcolo formale del Codice Fiscale

The ability to perform a true deep copy of an object is a classic requirement for most software developers. For those who need to understand the key difference between a deep copy and a shallow copy of an object, let's quickly summarize it:

  • A Deep Copy is a second instance (B) of the source object (A) with the same values: all (A) properties are also deeply copied as well into (B), meaning that there will be no cross-references between (A) properties and (B) properties: for example, if you alter  B.Property ,  A.Property won't be affected.
  • A Shallow Copy, also known as field copy, will also create a second instance (B) of the source object (A), but will copy all the fields values of the source object (A) over to (B) without creating a new instance of them. When the field value is a primitive type there won't be any difference with the previous method: however, whenever the field's value is a reference to an object (e.g., a memory address) such method will copy the reference, hence referring to the same object as A does. The referenced objects are thus shared, so if one of these objects is modified (from A or B), the change is visible in the other.

When it comes to coding a shallow copy is simple and typically easy to pull off, as they can be usually implemented by simply copying the bits exactly: in C# it can even be done with an one-liner, thanks to the native MemberwiseClone object method. Conversely, a deep copy will take additional work and is more resource-intensive, expecially when we're talking about big object (with significative references).

Among the many approaches offered by C# to achieve this, here are two of the most used methods: the BinaryFormatter approach and the Recursive MemberwiseClone way. In this article we'll try our best to briefly review both of them.

Method #1: BinaryFormatter

As the comments say, our class must be marked as [Serializable] and have a default, parameter-less constructor in order for this approach to work. Our source file must also reference the following namespaces:

Method #2: Recursive MemberwiseClone

The same result can be achieved using a recursive call to the aforementioned MemberwiseClone native C# function. Such approach that has some performance benefits over the BinaryFormatter one: it's 2x/3x times faster and it doesn't require a default parameter-less constructor or any attributes. The only downside is that the efforts in writing the actula code, because we need to manually iterate through the various members and compare them using a custom-made IComparer.

Luckily enough, there's a great GitHub object extensions class written by Alexey Burtsev that does all that in a neat way: the code is released under a MIT-license, meaning that it can be used in any project as long as the author's credits are mantained.

Here's our slightly modified version of that class:

In order for this to work properly we also need to add a couple more pieces of code within the same namespace.

A custom EqualityComparer:

And the following extension method for the Array type, together with an ArrayTraverse internal class that will be used to traverse through the array-types references (if any):

That's it for now: we sincerely hope that this post will help many C# developers looking for a neat way to deep-clone their objects!


About Ryan

IT Project Manager, Web Interface Architect and Lead Developer for many high-traffic web sites & services hosted in Italy and Europe. Since 2010 it's also a lead designer for many App and games for Android, iOS and Windows Phone mobile devices for a number of italian companies. Microsoft MVP for Development Technologies since 2018.

View all posts by Ryan

3 Comments on “How to perform a Deep Copy / Deep Clone of an object in ASP.NET C#”

  1. Pingback: Copy nested object – Autocad Space

Leave a Reply

Your email address will not be published. Required fields are marked *

The reCAPTCHA verification period has expired. Please reload the page.

This site uses Akismet to reduce spam. Learn how your comment data is processed.