您的位置:首页 > 其它

对象的深拷贝-序列化拷贝

2016-03-17 18:23 316 查看
简介:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: