C# 深拷贝浅拷贝
来源:互联网 发布:手机淘宝怎么换购 编辑:程序博客网 时间:2024/04/29 00:08
为对象创建副本的技术称为拷贝(也叫克隆)。我们将拷贝分为浅拷贝和深拷贝。
浅拷贝 将对象中的所有字段复制到新的对象(副本)中。其中,值类型字段的值被复制到副本中后,在副本中的修改不会影响到源对象对应的值。而引用类型的字段被复制到副本中的是引用类型的引用,而不是引用的对象,在副本中对引用类型的字段值做修改会影响到源对象本身。
深拷贝 同样,将对象中的所有字段复制到新的对象中。不过,无论是对象的值类型字段,还是引用类型字段,都会被重新创建并赋值,对于副本的修改,不会影响到源对象本身。
无论是浅拷贝还是深拷贝,微软都建议用类型继承ICloneable接口的方式明确告诉调用者:该类型可以被拷贝。当然,ICloneable接口只提供了一个声明为Clone的方法,我们可以根据需求在Clone方法内实现浅拷贝或深拷贝。
如下,构造两个类,使用默认拷贝函数,代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.IO;using System.Runtime.Serialization;using System.Runtime.Serialization.Formatters.Binary;namespace DeepLowClone{ [Serializable] public class Student:ICloneable { #region imp Iclone public object Clone() { return this.MemberwiseClone(); } #endregion imp Iclone private String mName; public String Name { get { return mName; } set { mName = value; } } private Department mDepartment; public Department OwnedDepartment { get { return mDepartment; } set { mDepartment = value; } } private String mStudentID; public String StudentID { get { return mStudentID; } set { mStudentID = value; } } private double mTotalScore; public double TotalScore { get { return mTotalScore; } set { mTotalScore = value; } } } [Serializable] public class Department { private String mName; public String Name { get { return mName; } set { mName = value; } } private String mID; public String DepID { get { return mID; } set { mID = value; } } }}
测试代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace DeepLowClone{ class Program { static void Main(string[] args) { Student std1 = new Student() { Name = "jane", TotalScore = 600.0, StudentID ="040432", OwnedDepartment = new Department { Name="gis", DepID="04" } }; PrintStudentInfo(std1); { Console.WriteLine("{0},{1} at Department({2} {3}) total score is {4};", std.StudentID, std.Name, std.OwnedDepartment.DepID, std.OwnedDepartment.Name, std.TotalScore); } }}
我们可以看到,当对源对象std1的StudentID 及Score作修改之后,副本对象的这两个属性并没有被修改过来,而对std2的Department对象的修改则反应到副本对象上。按浅拷贝的概念,StudentID和Department一样是引用类型,副本应该会保持和源对象一样,但是结果并不是这样。理论上string类型是引用类型,但是由于该引用类型的特殊性(无论是实现还是语义),Object.MemberwiseClone方法仍旧为其创建了副本。也就是说,在浅拷贝过程,我们应该将字符串看成是值类型。
为了实现对象的完全拷贝,我们重写Clone如下:
#region imp Iclone //public object Clone() //{ // return this.MemberwiseClone(); //} public object Clone() { Student cloneobj; using (Stream ms = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); // serialize the obj as stream formatter.Serialize(ms, this); ms.Seek(0, SeekOrigin.Begin); //De-serialize the stream to obj cloneobj = formatter.Deserialize(ms) as Student; ms.Close(); } return cloneobj; } #endregion imp Iclone
使用该方法进行深拷贝时,所有类型都必须标识为Serializable否则formatter.Serialize(ms,this)语句将报异常这样的异常An unhandled exception of type 'System.Runtime.Serialization.SerializationException' occurred in mscorlib.dll
运行结果如下:
我们可以看到源对象的修改不再影响副本。
以上我们是利用二进制序列化和反序列化实现深拷贝的。我们也可以手动对字段逐个进行赋值。但这种方法容易出错,也就是说,如果类型的字段发生变化或有增减,那么该拷贝方法也要发生相应的变化。
另外还可以通过反射及xml序列化反序列化来实现深拷贝。详见
http://www.cnblogs.com/yuilin/archive/2011/10/28/2227881.html。
Ref:
http://book.51cto.com/art/201109/292343.htm
- C# 深拷贝/浅拷贝
- C# 深拷贝 浅拷贝
- C# 深拷贝浅拷贝
- c#深拷贝与浅拷贝
- 转载 C# 深拷贝与浅拷贝
- c#深拷贝与浅拷贝
- c#深拷贝与浅拷贝
- c#深拷贝与浅拷贝
- 浅析C#深拷贝与浅拷贝
- 浅析C#深拷贝与浅拷贝
- c#深拷贝与浅拷贝
- C# 浅拷贝与深拷贝区别
- 浅析C#深拷贝与浅拷贝
- C# 浅拷贝与深拷贝区别
- C#中浅拷贝与深拷贝
- c#深拷贝与浅拷贝
- C# 浅拷贝与深拷贝
- c#深拷贝与浅拷贝 .
- 3.Digit Counts-统计数字(中等题)
- Ubuntu16.04下安装matlab2014a
- 数据结构 之二分法查找
- CCF真题——Z字形扫描(java)
- 常量指针与指针常量的区别
- C# 深拷贝浅拷贝
- Python 读取csv的某列
- CONCAT(SUBSTRING(m.USER_NAME,1,1),'***') AS `USER_NAME`
- 【Android】详解7.0带来的新工具类:DiffUtil
- 清除浮动
- SVN版本服务器搭建(服务端+客户端)
- poj 1679 The Unique MST
- Xcode 8来了 所以 UITableView...
- Linux-Shell脚本编程-学习-3-Shell编程-shell脚本基本格式