簡介:this
System.Object 幾乎是全部的類、結構、委託類型的基類。System.Object有一個MemberwiseClone 的方法來幫助咱們建立一個當前對象的實例。spa
存在的問題:code
System.Object 提供的MemberwiseClone 方法只是對象的淺拷貝,只能把當前對象的非靜態字段拷貝到新對象。若是屬性是值類型,那麼就把值拷貝一份,若是是引用類型,那麼只拷貝對原對象的引用。這就意味着MemberwiseClone 不可以建立對象的深拷貝。orm
解決方案:對象
有不少實現深拷貝的方式,在這裏我只介紹其中的2種。blog
1.經過序列化和反序列化實現深拷貝。接口
2.經過反射來實現深拷貝。get
今天我就先介紹第一種:序列化和反序列化實現深拷貝。string
ICloneable 接口提供給咱們一個能夠自定義實現拷貝的Clone方法。it
序列化就是把對象轉換成字節流的過程,反序列化相反,就是把字節流轉換成原對象的過程。在.NET中有不少序列化的方式,好比二進制序列化、XML序列化等等。二進制序列化要比XML序列化快得多。因此二進制序列化是比較好的序列化和反序列化。
經過序列化和反序列化,可以實現對一個對象的深拷貝,可是前提是須要序列化和反序列化的類都要標記爲serializable特性。
下面的例子,我建立一個職員類,擁有一個部門屬性。
1 [Serializable] 2 public class Department 3 { 4 public int DepartmentId { get; set; } 5 public string DepartmentName { get; set; } 6 }
1 [Serializable] 2 public class Employee : ICloneable 3 { 4 public int EmployeeId { get; set; } 5 public string EmployeeName { get; set; } 6 public Department Department { get; set; } 7 8 public object Clone() 9 { 10 using (MemoryStream stream = new MemoryStream()) 11 { 12 if (this.GetType().IsSerializable) 13 { 14 BinaryFormatter formatter = new BinaryFormatter(); 15 formatter.Serialize(stream, this); 16 stream.Position = 0; 17 return formatter.Deserialize(stream); 18 } 19 return null; 20 } 21 } 22 }
看到咱們用二進制序列化和反序列化實現了IClone接口的Clone方法。這個Clone方法咱們能夠提出來做爲一個擴展方法:
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 }
看源代碼:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.IO; 6 using System.Runtime.Serialization.Formatters.Binary; 7 8 namespace SerializeCopy 9 { 10 [Serializable] 11 public class Department 12 { 13 public int DepartmentId { get; set; } 14 15 public string DepartmentName { get; set; } 16 } 17 18 [Serializable] 19 public class Employee : ICloneable 20 { 21 public int EmployeeId { get; set; } 22 public string EmployeeName { get; set; } 23 public Department Department { get; set; } 24 25 public Object Clone() 26 { 27 28 return ObjectExtension.CopyObject<Employee>(this); 29 } 30 31 } 32 public static class ObjectExtension 33 { 34 35 public static T CopyObject<T>(this object objsource) 36 { 37 using (MemoryStream stream = new MemoryStream()) 38 { 39 BinaryFormatter formatter = new BinaryFormatter(); 40 41 formatter.Serialize(stream, objsource); 42 stream.Position = 0; 43 44 return (T)formatter.Deserialize(stream); 45 46 } 47 48 } 49 50 } 51 52 }
調用代碼:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SerializeCopy 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 Employee emp = new Employee(); 13 14 emp.EmployeeId = 1000; 15 emp.EmployeeName = "IT少年"; 16 emp.Department = new Department { DepartmentId = 1, DepartmentName = "Examination" }; 17 18 Employee empclone = emp.Clone() as Employee; 19 20 emp.EmployeeId = 1003; 21 emp.EmployeeName = "TTT"; 22 emp.Department.DepartmentId = 3; 23 emp.Department.DepartmentName = "admin"; 24 Console.WriteLine("----emp原始對象------"); 25 Console.WriteLine("拷貝前DepartmentName應該是admin: " + emp.Department.DepartmentName); 26 Console.WriteLine("拷貝前DepartmentID應該是3: " + emp.Department.DepartmentId); 27 28 Console.WriteLine("----empclone拷貝對象------"); 29 Console.WriteLine("拷貝DepartmentName應該是Examination: " + empclone.Department.DepartmentName); 30 Console.WriteLine("拷貝DepartmentID應該是1: " + empclone.Department.DepartmentId); 31 Console.ReadKey(); 32 } 33 } 34 }
調用結果:
須要注意的一點是,用序列化和反序列化深拷貝,須要將須要拷貝的屬性標記爲Serializable