A deep copy of C# Object

Recommended for you: Get network issues from WhatsUp Gold. Not end users.

Introduction:

C#System.Object is all class types, structure types, the base class enumeration type and a delegate type. It is the basis of type inheritance. System.Object includes a for a copy of the members of the MemberwiseClone method to create the object instances.

Problem description:

Create a MemberwiseClone System.Object a new object of the shallow copy, and the non static field in the current instance of the object and copy to the new object instances. Through the attribute, object copying can correctly perform: if a property is a value type, then the bitwise copy data, if the property is a reference type, then copy the original object, that is to say, the cloned object pointing to the same object instance. This means that a deep copy of MemberwiseClone method does not create an object.

Solution:

There are many methods to achieve deep copy of an object of the class, I will introduce two of them by example:

  1 through serialization deserialization, deep copy

  2 through the reflection to achieve a deep copy

1,Through the serialization, deep copy to deserialize the object

The ICloneable interface allows developers to customize the implementation of the Clone method is used to create a deep copy stored objects. Usually the Object.MemberwiseClone method to help developers create a stored copy of the object, but creating a shallow copy of the object. Serialization refers to the process object state is stored as a binary stream, and deserialization refers to the binary stream conversion process for the original object. In.Net there are many ways to achieve serialization and deserialization, such as binary serialization, XML serialization, data contract serialization etc. Binary serialization serialization than XML fast, and binary serialization using private, public fields, and binary serialization is to achieve serialization and deserialization good choice.

The serialization and deserialization, a deep copy of the object can be created. Of note, all types of only labeled [serializable] properties can realize serialization and deserialization.

Sample program:

First, create a Employee class, which contains the attribute of type Department, Employee classes inherit from the ICloneable interface and implementation of the Clone method. Using the binary formatter (binary formater), to achieve the object serialization and deserialization is a new object.

 1 [Serializable]
 2     public class Department
 3     {
 4         private Int32 _DepartmentID;
 5         private String _DepartmentName;
 6         public Int32 DepartmentID 
 7         {
 8             get {return _DepartmentID;}
 9             set { _DepartmentID = value;}
10         }
11         public String DepartmentName
12         {
13             get {return _DepartmentName;}
14             set {_DepartmentName = value;}
15         }
16     }
17      [Serializable]
18     public class Employee : ICloneable
19     {
20           private Int32 _EmployeeID;
21           private String _EmployeeName;
22           private Department _Dempartment;
23         public Int32 EmployeeID 
24         { 
25             get {return _EmployeeID;} 
26             set {_EmployeeID = value; }
27         }
28         public String EmployeeName 
29         { 
30             get { return _EmployeeName; }
31             set { _EmployeeName = value;} 
32         }
33         public Department Department 
34         { 
35             get{ return _Dempartment; } 
36             set{ _Dempartment= value;} 
37         }
38 
39         public object Clone()
40         {
41             using (MemoryStream stream = new MemoryStream())
42             {
43                 if (this.GetType().IsSerializable)
44                 {
45                     BinaryFormatter formatter = new BinaryFormatter();
46                     formatter.Serialize(stream, this);
47                     stream.Position = 0;
48                     return formatter.Deserialize(stream);
49                 }
50                 return null;
51             }
52         }
53     }

View Code

Can also be achieved by expansion method:

 1 public static class ObjectExtension
 2     {
 3         public static T CopyObject<T>(this object objSource)
 4         {
 5             using (MemoryStream stream = new MemoryStream())
 6             {
 7                 BinaryFormatter formatter = new BinaryFormatter();
 8                 formatter.Serialize(stream, objSource);
 9                 stream.Position = 0;
10                 return (T)formatter.Deserialize(stream);
11             }
12         }
13     }

2 through the reflection to achieve a deep copy

Reflection is used to obtain the runtime object primitive information. Using the System.Reflection name space can be acquired when the object class history information, from the existing object to create an instance of a type, and access its properties and call the method. Consider the code, I create a static method that accepts a Object parameter, and returns a new instance of the same type.

 1  public class Utility
 2     {
 3         public static object CloneObject(object objSource)
 4         {
 5             //Get the type of source object and create a new instance of that type
 6             Type typeSource = objSource.GetType();
 7             object objTarget = Activator.CreateInstance(typeSource);
 8 
 9             //Get all the properties of source object type
10             PropertyInfo[] propertyInfo = typeSource.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
11 
12             //Assign all source property to taget object 's properties
13             foreach (PropertyInfo property in propertyInfo)
14             {
15                 //Check whether property can be written to 
16                 if (property.CanWrite)
17                 {
18                     //check whether property type is value type, enum or string type
19                     if (property.PropertyType.IsValueType || property.PropertyType.IsEnum || property.PropertyType.Equals(typeof(System.String)))
20                     {
21                         property.SetValue(objTarget, property.GetValue(objSource, null), null);
22                     }
23                     //else property type is object/complex types, so need to recursively call this method until the end of the tree is reached
24                     else
25                     {
26                         object objPropertyValue = property.GetValue(objSource, null);
27                         if (objPropertyValue == null)
28                         {
29                             property.SetValue(objTarget, null, null);
30                         }
31                         else
32                         {
33                             property.SetValue(objTarget, CloneObject(objPropertyValue), null);
34                         }
35                     }
36                 }
37             }
38             return objTarget;
39         }
40     }

This can also be achieved by extending the method.

 1  public static class ObjectExtension
 2     {
 3         public static object CloneObject(this object objSource)
 4         {
 5             //Get the type of source object and create a new instance of that type
 6             Type typeSource = objSource.GetType();
 7             object objTarget = Activator.CreateInstance(typeSource);
 8 
 9             //Get all the properties of source object type
10             PropertyInfo[] propertyInfo = typeSource.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
11 
12             //Assign all source property to taget object 's properties
13             foreach (PropertyInfo property in propertyInfo)
14             {
15                 //Check whether property can be written to 
16                 if (property.CanWrite)
17                 {
18                     //check whether property type is value type, enum or string type
19                     if (property.PropertyType.IsValueType || property.PropertyType.IsEnum || property.PropertyType.Equals(typeof(System.String)))
20                     {
21                         property.SetValue(objTarget, property.GetValue(objSource, null), null);
22                     }
23                     //else property type is object/complex types, so need to recursively call this method until the end of the tree is reached
24                     else
25                     {
26                         object objPropertyValue = property.GetValue(objSource, null);
27                         if (objPropertyValue == null)
28                         {
29                             property.SetValue(objTarget, null, null);
30                         }
31                         else
32                         {
33                             property.SetValue(objTarget, objPropertyValue.CloneObject(), null);
34                         }
35                     }
36                 }
37             }
38             return objTarget;
39         }
40     }

The following is a sample code and output:

 1 class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Employee emp = new Employee();
 6             emp.EmployeeID = 1000;
 7             emp.EmployeeName = "Cacotopia";
 8             emp.Department = new Department { DepartmentID = 1, DepartmentName = "development center" };
 9 
10             Employee empClone = emp.Clone() as Employee;
11 
12             Employee empClone1 = Utility.CloneObject(emp) as Employee;
13             Employee empClone2 = emp.CloneObject() as Employee;
14 
15             Employee empClone3 = emp.CopyObject<Employee>();
16             //now Change Original Object Value
17             emp.EmployeeName = "24/7";
18             emp.Department.DepartmentName = "Admin";
19 
20             //Print origianl as well as clone object properties value.
21 
22             Console.WriteLine("Original Employee Name : " + emp.EmployeeName);
23             Console.WriteLine("Original Department Name : " + emp.Department.DepartmentName);
24 
25             Console.WriteLine("");
26 
27             Console.WriteLine("Clone Object Employee Name (Clone Method) : " + empClone.EmployeeName);
28             Console.WriteLine("Clone Object Department Name (Clone Method) : " + empClone.Department.DepartmentName);
29 
30             Console.WriteLine("");
31 
32             Console.WriteLine("Clone Object Employee Name (Static Method) : " + empClone1.EmployeeName);
33             Console.WriteLine("Clone Object Department Name (Static Method) : " + empClone1.Department.DepartmentName);
34 
35             Console.WriteLine("");
36 
37             Console.WriteLine("Clone Object Employee Name (Extension Method) : " + empClone2.EmployeeName);
38             Console.WriteLine("Clone Object Department Name (Extension Method) : " + empClone2.Department.DepartmentName);
39             Console.WriteLine("press any key to exit...");
40             Console.ReadKey();
41         }
42     }

Conclusion:

A deep copy of the serialization and reflection we can achieve the object. Using serialization only deficiencies deep copy of the object is marked as Serializable that must be.
















Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by Arlen at November 15, 2013 - 5:33 PM