对象的深拷贝

时间:2022-10-10 19:57:00

简介:

System.Object 几乎是所有的类、结构、委托类型的基类。System.Object有一个MemberwiseClone 的方法来帮助我们创建一个当前对象的实例。

存在的问题:

System.Object 提供的MemberwiseClone 方法只是对象的浅拷贝,只能把当前对象的非静态字段拷贝到新对象。如果属性是值类型,那么就把值拷贝一份,如果是引用类型,那么只拷贝对原对象的引用。这就意味着MemberwiseClone 不能够创建对象的深拷贝。

解决方案:

有很多实现深拷贝的方式,在这里我只介绍其中的2种。

1.通过序列化和反序列化实现深拷贝。

2.通过反射来实现深拷贝。

今天我就先介绍第一种:序列化和反序列化实现深拷贝。

ICloneable 接口提供给我们一个可以自定义实现拷贝的Clone方法。

序列化就是把对象转换成字节流的过程,反序列化相反,就是把字节流转换成原对象的过程。在.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