也谈.NET中的深复制和浅复制
声明:本文系作者原创,转载请声明转自http://home.cnblogs.com/u/sunt2012/ 谢谢合作
- 话题由起:该话题源于最近一次参加其他项目组的的技术分享之原型模式中关于深复制和浅复制的实现
- 主讲人的观点:浅复制没有什么疑问,概念上来说没有什么疑问(其实在实现上来说我还是有点点儿疑问,一会儿再说)。关于深复制的实现方式如下(只贴关键代码,不去评价其好坏,只是为了阐述我的疑问):
public object Clone() { DeepClone _deepClone = new DeepClone(); //TODO:_deepClone的属性赋值 _deepClone.TestObject = new TestObject(); //TODO:_deepClone的TestObject的属性赋值 Console.WriteLine("DeepClone的拷贝完成了"); return _deepClone; }
- 我的疑问:
1、关于MemberwiseClone()方法,是否会调用构造函数?
2、原型模式中有主要的一个词“复制”,那么,复制和new构造函数有何区别,是只是要求提供一个clone方法么 ?
3、如果原型类是一个引用对象,那么MemberwiseClone()返回的实例是否和this指代的是一个实例,如果不是,为什么会有这样的一句“DeepClone _deepClone = new DeepClone();”?
这些疑问在这次分享上并没有得到满意的答复,所以回来之后我研究了一下这方面得知识,算是长了点儿见识,同时也把我的收获给分享一下 - 我的实例,为了得到答案,我做了如下的一个实例:
public class DeepClone:ICloneable { public TestObject TestObject { get; set; } public DeepClone() { TestObject = new TestObject(); Console.WriteLine("DeepClone的构造函数执行了"); } public object Clone() { DeepClone _deepClone = (DeepClone)this.MemberwiseClone(); _deepClone.TestObject = (TestObject)this.TestObject.Clone(); Console.WriteLine("DeepClone的拷贝完成了"); return _deepClone; } } public class ShallowClone:ICloneable { public TestObject TestObject { get; set; } public ShallowClone() { TestObject = new TestObject(); Console.WriteLine("DeepClone的构造函数执行了"); } public object Clone() { return this.MemberwiseClone(); } } public class TestObject:ICloneable { public int ObjectVaule{ get; set; } /// <summary> /// 用于测试执行clone时,是否会执行构造函数 /// </summary> public TestObject() { this.ObjectVaule = 100; Console.WriteLine("TestObject的构造函数执行了"); } public object Clone() { return this.MemberwiseClone(); } }
,测试方法如下:
static void Main(string[] args) { Console.WriteLine("测试深拷贝"); DeepClone _deep = new DeepClone(); DeepClone _deepClone = (DeepClone)_deep.Clone(); _deepClone.TestObject.ObjectVaule = 1000; Console.WriteLine("原对象值={0},拷贝对象值={1},是否引用的一个对象:{2}", _deep.TestObject.ObjectVaule, _deepClone.TestObject.ObjectVaule, _deep.TestObject.Equals(_deepClone.TestObject)); Console.WriteLine("测试浅拷贝"); ShallowClone _shall = new ShallowClone(); ShallowClone _shallClone = (ShallowClone)_shall.Clone(); _shallClone.TestObject.ObjectVaule = 1000; Console.WriteLine("原对象值={0},拷贝对象值={1},是否引用的一个对象:{2},原对象是否等于拷贝对象{3}", _shall.TestObject.ObjectVaule, _shallClone.TestObject.ObjectVaule, _shallClone.TestObject.Equals(_shallClone.TestObject),_shall.Equals(_shallClone)); Console.ReadKey(); }
运行结果如图:
结果:1、MemberwiseClone()并未执行构造函数
2、拷贝对象和元对象不是同一个实例
3、原型模式的意义在于对象复制,个人认为对象的引用属性的复制也应该是clone,而不是new,当然,若引用的属性只能用new了(个人见解,勿喷)
又来疑问:MemberwiseClone()既然未调用构造函数,那么新对象是如何生成的呢?
解答:这要从.NET引用类型在内存中的分配来说了。
通过《CLR via C#》得知,引用类型分配到托管堆上,堆上分配的每个对象都有一些额外成员,这些成员必须初始化。这些成员包括“类型对象指针”和“同步索引块”,这些成员由CLR用于管理对象。
MemberwiseClone()的作用是分配内存,初始化对象的附加子段,然后将源对象的字节数据复制到新对象中。