How to deep clone objects in C#
Deep cloning an object in C# involves duplicating the object and copies of all objects that the original object references. This assures that modifications to the clone don’t impact the original and vice versa. There are several methods to deep clone objects in C#, which include the following:
Serialization-based cloning
Manual deep clone
Using deep copy libraries
Serialization-based cloning
In serialization-based cloning, an object is converted to an intermediary format (usually a string or binary format) and then reconstructed into a new object. This approach guarantees a deep copy of the object, meaning all nested objects are duplicated, and no references to the original nested objects remain. Here is an example of the CourseCatalogue in which we’ll use the Newtonsoft.Json library for serialization and deserialization:
using System;using Newtonsoft.Json;namespace DeepCopyJsonNet{class Program{static void Main(string[] args){// Creating an instance of CourseCataloguevar courseCatalogue = new CourseCatalogue{CourseTitle = "Introduction to Programming",CourseDetails = new CourseDetails { DurationInHours = 40, Instructor = "Dr. Smith" }};// Deep cloning using Newtonsoft.Jsonvar clonedCatalogue = DeepClone(courseCatalogue) ?? new CourseCatalogue();// Modifying the cloned objectclonedCatalogue.CourseTitle = "Advanced Programming";// Ensure CourseDetails is not null before modifying its propertiesif (clonedCatalogue.CourseDetails != null){clonedCatalogue.CourseDetails.Instructor = "Prof. Johnson";}else{clonedCatalogue.CourseDetails = new CourseDetails { DurationInHours = 0, Instructor = "Prof. Johnson" };}// Printing original and cloned object's propertiesConsole.WriteLine("Original object:");Console.WriteLine(courseCatalogue.CourseTitle);Console.WriteLine(courseCatalogue.CourseDetails?.Instructor);Console.WriteLine("\nModified cloned object:");Console.WriteLine(clonedCatalogue?.CourseTitle);Console.WriteLine(clonedCatalogue?.CourseDetails?.Instructor);}// Deep clone method using Newtonsoft.Json serialization and deserializationpublic static T? DeepClone<T>(T obj) where T : class{string json = JsonConvert.SerializeObject(obj);return JsonConvert.DeserializeObject<T>(json);}}public class CourseCatalogue{public string? CourseTitle { get; set; }public CourseDetails? CourseDetails { get; set; }}public class CourseDetails{public int DurationInHours { get; set; }public string? Instructor { get; set; }}}
Here’s a concise breakdown of the essential lines in the code:
Lines 11–15: We create an instance of
CourseCataloguewith its properties set.Line 18: We use the
DeepClonemethod to deep clone thecourseCatalogueobject. If the cloned result isnull, it initializes a newCourseCatalogue.Lines 21–31: We modify properties of the cloned object:
CourseTitleand potentiallyCourseDetails.Instructor.Lines 34–40: We print properties of both the original and cloned objects to the console.
Line 46: We serialize the object to a JSON string using
JsonConvert.SerializeObject.Line 47: We deserialize the JSON string to the object, creating a deep clone.
This approach is straightforward and doesn’t require manually copying each property or field. It ensures nested objects are cloned, completely separate from the original instance. We can easily clone objects without knowing their internal structure with serialization-based cloning. However, serialization and deserialization can be slower for oversized items than alternative cloning methods.
Manual deep clone
In this method, we manually copy the attributes to the new object.
using System;namespace ManualCloneExample{class Program{static void Main(string[] args){// Creating an instance of CourseCataloguevar courseCatalogue = new CourseCatalogue{CourseTitle = "Introduction to Programming",CourseDetails = new CourseDetails { DurationInHours = 40, Instructor = "Dr. Smith" }};// Deep cloning manuallyvar clonedCatalogue = courseCatalogue.DeepCopy();// Modifying the cloned objectclonedCatalogue.CourseTitle = "Advanced Programming";// Ensure CourseDetails isn't null before modifying its propertiesif (clonedCatalogue.CourseDetails != null){clonedCatalogue.CourseDetails.Instructor = "Prof. Johnson";}// Printing original and cloned object's propertiesConsole.WriteLine("Original object:");Console.WriteLine(courseCatalogue.CourseTitle);Console.WriteLine(courseCatalogue.CourseDetails?.Instructor);Console.WriteLine("\nModified cloned object:");Console.WriteLine(clonedCatalogue?.CourseTitle);Console.WriteLine(clonedCatalogue?.CourseDetails?.Instructor);}}public class CourseCatalogue{public string? CourseTitle { get; set; } // made nullablepublic CourseDetails? CourseDetails { get; set; } // made nullable// Manual deep copy methodpublic CourseCatalogue DeepCopy(){return new CourseCatalogue{CourseTitle = this.CourseTitle,CourseDetails = this.CourseDetails != null ?new CourseDetails{DurationInHours = this.CourseDetails.DurationInHours,Instructor = this.CourseDetails.Instructor}: null};}}public class CourseDetails{public int DurationInHours { get; set; }public string? Instructor { get; set; } // made nullable}}
Here’s a concise breakdown of the essential lines in the provided code:
Lines 10–14: We create an instance of
CourseCataloguewith its properties set.Line 17: We use the
DeepCopymethod ofCourseCatalogueto manually deep clone thecourseCatalogueobject.Lines 20–26: We modify the cloned object’s
CourseTitleand potentiallyCourseDetails.Instructor.Lines 29–35: We print the properties of the original and cloned objects to the console.
Manual cloning is error-prone, especially as object structures evolve, leading to maintenance challenges and potential inconsistencies. This method often results in verbose code and needs help with nuances like circular references, typically handled in third-party libraries.
Using deep copy libraries
Some libraries can help with deep cloning without manually coding for every object. For example, CloneExtensions, Automapper, ObjectCloner, DeepCloner, and ExpressMapper.
Let’s see an example of using CloneExtensions:
using System;using CloneExtensions;namespace CloneExtensionsExample{class Program{static void Main(string[] args){// Creating an instance of CourseCataloguevar courseCatalogue = new CourseCatalogue{CourseTitle = "Introduction to Programming",CourseDetails = new CourseDetails { DurationInHours = 40, Instructor = "Dr. Smith" }};// Deep cloning using CloneExtensions libraryvar clonedCatalogue = courseCatalogue.GetClone();// Modifying the cloned objectif (clonedCatalogue != null){clonedCatalogue.CourseTitle = "Advanced Programming";if (clonedCatalogue.CourseDetails != null){clonedCatalogue.CourseDetails.Instructor = "Prof. Johnson";}}// Printing original and cloned object's propertiesConsole.WriteLine("Original object:");Console.WriteLine(courseCatalogue.CourseTitle);Console.WriteLine(courseCatalogue.CourseDetails?.Instructor);Console.WriteLine("\nModified cloned object:");Console.WriteLine(clonedCatalogue?.CourseTitle);Console.WriteLine(clonedCatalogue?.CourseDetails?.Instructor);}}public class CourseCatalogue{public string? CourseTitle { get; set; } // made nullablepublic CourseDetails? CourseDetails { get; set; } // made nullable}public class CourseDetails{public int DurationInHours { get; set; }public string? Instructor { get; set; } // made nullable}}
Here’s a concise explanation of the provided code:
Line 18: The
CourseCatalogueobject is deeply cloned using theGetClone()method from theCloneExtensionslibrary.Lines 21–28: The cloned object’s course title is modified to
"Advanced Programming". If the cloned object’sCourseDetailsis not null, the instructor is changed to"Prof. Johnson".Lines 31–37: The original and cloned object properties, specifically the course title and instructor name, are printed on the console.
The GetClone() method is provided by the CloneExtensions library, which allows for the deep cloning of objects.
Free Resources