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
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 CourseCatalogue
with its properties set.
Line 18: We use the DeepClone
method to deep clone the courseCatalogue
object. If the cloned result is null
, it initializes a new CourseCatalogue
.
Lines 21–31: We modify properties of the cloned object: CourseTitle
and potentially CourseDetails.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.
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 CourseCatalogue
with its properties set.
Line 17: We use the DeepCopy
method of CourseCatalogue
to manually deep clone the courseCatalogue
object.
Lines 20–26: We modify the cloned object’s CourseTitle
and potentially CourseDetails.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.
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 CourseCatalogue
object is deeply cloned using the GetClone()
method from the CloneExtensions
library.
Lines 21–28: The cloned object’s course title is modified to "Advanced Programming"
. If the cloned object’s CourseDetails
is 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