對象的深拷貝-序列化拷貝

簡介: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

相關文章
相關標籤/搜索