对象的深拷贝-序列化拷贝
2016-03-17 18:23
316 查看
简介:
System.Object 几乎是所有的类、结构、委托类型的基类。System.Object有一个MemberwiseClone 的方法来帮助我们创建一个当前对象的实例。
存在的问题:
System.Object 提供的MemberwiseClone 方法只是对象的浅拷贝,只能把当前对象的非静态字段拷贝到新对象。如果属性是值类型,那么就把值拷贝一份,如果是引用类型,那么只拷贝对原对象的引用。这就意味着MemberwiseClone 不能够创建对象的深拷贝。
解决方案:
有很多实现深拷贝的方式,在这里我只介绍其中的2种。
1.通过序列化和反序列化实现深拷贝。
2.通过反射来实现深拷贝。
今天我就先介绍第一种:序列化和反序列化实现深拷贝。
ICloneable 接口提供给我们一个可以自定义实现拷贝的Clone方法。
序列化就是把对象转换成字节流的过程,反序列化相反,就是把字节流转换成原对象的过程。在.NET中有很多序列化的方式,比如二进制序列化、XML序列化等等。二进制序列化要比XML序列化快得多。所以二进制序列化是比较好的序列化和反序列化。
通过序列化和反序列化,能够实现对一个对象的深拷贝,但是前提是需要序列化和反序列化的类都要标记为serializable特性。
下面的例子,我创建一个职员类,拥有一个部门属性。
看到我们用二进制序列化和反序列化实现了IClone接口的Clone方法。这个Clone方法我们可以提出来作为一个扩展方法:
看源代码:
调用代码:
调用结果:
需要注意的一点是,用序列化和反序列化深拷贝,需要将需要拷贝的属性标记为Serializable
System.Object 几乎是所有的类、结构、委托类型的基类。System.Object有一个MemberwiseClone 的方法来帮助我们创建一个当前对象的实例。
存在的问题:
System.Object 提供的MemberwiseClone 方法只是对象的浅拷贝,只能把当前对象的非静态字段拷贝到新对象。如果属性是值类型,那么就把值拷贝一份,如果是引用类型,那么只拷贝对原对象的引用。这就意味着MemberwiseClone 不能够创建对象的深拷贝。
解决方案:
有很多实现深拷贝的方式,在这里我只介绍其中的2种。
1.通过序列化和反序列化实现深拷贝。
2.通过反射来实现深拷贝。
今天我就先介绍第一种:序列化和反序列化实现深拷贝。
ICloneable 接口提供给我们一个可以自定义实现拷贝的Clone方法。
序列化就是把对象转换成字节流的过程,反序列化相反,就是把字节流转换成原对象的过程。在.NET中有很多序列化的方式,比如二进制序列化、XML序列化等等。二进制序列化要比XML序列化快得多。所以二进制序列化是比较好的序列化和反序列化。
通过序列化和反序列化,能够实现对一个对象的深拷贝,但是前提是需要序列化和反序列化的类都要标记为serializable特性。
下面的例子,我创建一个职员类,拥有一个部门属性。
[Serializable] public class Department { public int DepartmentId { get; set; } public string DepartmentName { get; set; } }
[Serializable] public class Employee : ICloneable { public int EmployeeId { get; set; } public string EmployeeName { get; set; } public Department Department { get; set; } public object Clone() { using (MemoryStream stream = new MemoryStream()) { if (this.GetType().IsSerializable) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, this); stream.Position = 0; return formatter.Deserialize(stream); } return null; } } }
看到我们用二进制序列化和反序列化实现了IClone接口的Clone方法。这个Clone方法我们可以提出来作为一个扩展方法:
public static class ObjectExtension { public static T CopyObject<T>(this object objSource) { using (MemoryStream stream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, objSource); stream.Position = 0; return (T)formatter.Deserialize(stream); } } }
看源代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Runtime.Serialization.Formatters.Binary; namespace SerializeCopy { [Serializable] public class Department { public int DepartmentId { get; set; } public string DepartmentName { get; set; } } [Serializable] public class Employee : ICloneable { public int EmployeeId { get; set; } public string EmployeeName { get; set; } public Department Department { get; set; } public Object Clone() { return ObjectExtension.CopyObject<Employee>(this); } } public static class ObjectExtension { public static T CopyObject<T>(this object objsource) { using (MemoryStream stream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, objsource); stream.Position = 0; return (T)formatter.Deserialize(stream); } } } }
调用代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SerializeCopy { class Program { static void Main(string[] args) { Employee emp = new Employee(); emp.EmployeeId = 1000; emp.EmployeeName = "IT少年"; emp.Department = new Department { DepartmentId = 1, DepartmentName = "Examination" }; Employee empclone = emp.Clone() as Employee; emp.EmployeeId = 1003; emp.EmployeeName = "TTT"; emp.Department.DepartmentId = 3; emp.Department.DepartmentName = "admin"; Console.WriteLine("----emp原始对象------"); Console.WriteLine("拷贝前DepartmentName应该是admin: " + emp.Department.DepartmentName); Console.WriteLine("拷贝前DepartmentID应该是3: " + emp.Department.DepartmentId); Console.WriteLine("----empclone拷贝对象------"); Console.WriteLine("拷贝DepartmentName应该是Examination: " + empclone.Department.DepartmentName); Console.WriteLine("拷贝DepartmentID应该是1: " + empclone.Department.DepartmentId); Console.ReadKey(); } } }
调用结果:
需要注意的一点是,用序列化和反序列化深拷贝,需要将需要拷贝的属性标记为Serializable
相关文章推荐
- 《统计学习方法》李航著——第一章学习笔记
- Python核心编程笔记----Python对象
- 【Data Algorithms_Recipes for Scaling up with Hadoop and Spark】Chapter 7 Market Basket Analysis
- iOS9 SDK新特性
- redis学习笔记3--基本操作1
- SpringBoot接口服务处理Whitelabel Error Page
- 开启elastic search 脚本
- 网络通信编程
- Handler、Message、MessageQueue、 Looper、Handler Thread
- POJ 1287 Networking(最小生成树)
- iOS8 SDK新特性
- swift开发笔记23 引入百度地图
- Android&IOS实时抓包
- 杭电2068 RPG的错排
- "SetDestination" can only be called on an active agent that has been placed on a NavMesh.
- android自定义控件
- android学习路线
- HDU 连续最大积
- 利率计算v2.0--web版--软件工程
- POJ - 2533 Longest Ordered Subsequence(最长上升子序列)