本文共 3198 字,大约阅读时间需要 10 分钟。
问题起源:
昨天被同事问到一个浅拷贝与深拷贝区别的问题,说实在的,记得在学校时在书在看过相关概念区别。 只是,那时的在校生,又有几个能对书本上那写的尽量让鬼都看不懂知识能清晰的理解呢。 工作后虽然也有用到Clone相关的内容,不过也仅是应用,基础的概念还是没去仔细的理解,以于后来DataTable内部那不深不浅的架构拷贝都混和这些概念混在一起了。 曾经的以为:
让得一年多以前,我去面试,被一个人问到浅拷贝与深拷贝区别,我答:浅拷贝就是拷贝就是拷贝架构,不包括值,深拷贝就是连值也一同拷贝。 当我答出这样错误的答案时,对方没有纠正,反而似乎对我的答案还挺满意的。 唉,面试管自己不懂还问我这问题,还让我一直以为到现在都是这个样。 同事的质问:
接着同事说它的示例里,发现值是有拷贝的,于是我意识到我的认知是有问题了,我重新百度了一下。 网上乱七杂八的答案,让我得一个模糊的似乎正确的答案:浅拷贝不拷贝内部类的对象 引申出的错乱:
接着同事的疑问更一度把我引向这个容易迷乱的错误深渊:浅拷贝是对引用类型拷贝地址,对值类型直接进行拷贝。
最后,为了解惑,还是用示例来说话了:
class DemoClass : ICloneable { public int intValue = 1; public string strValue = "1"; public PersonEnum pEnum = PersonEnum.EnumA; public PersonStruct pStruct = new PersonStruct(); public Person pClass = new Person("1"); public int[] pIntArray = new int[] { 1 }; public string[] pArray = new string[] { "1" }; #region ICloneable 成员 public DemoClass() { pStruct.StructValue = 1; } public object Clone() { return this.MemberwiseClone(); } #endregion } class Person { public string Name; public Person(string name) { Name = name; } } public enum PersonEnum { EnumA=1, EnumB=2 } public struct PersonStruct { public int StructValue; } 说明:
int[] string[] enum struct class 然后接下来会产生实例A和克隆实例B。 接着改变B的值,看A的值会不会被改变。
接下我们看main方法
static void Main( string [] args) { Demo(); } public static void Demo() { DemoClass A = new DemoClass(); DemoClass B = (DemoClass)A.Clone(); B.intValue = 2 ; Write( string .Format( " int->[A:{0}] [B:{1}] " , A.intValue, B.intValue)); B.strValue = " 2 " ; Write( string .Format( " string->[A:{0}] [B:{1}] " , A.strValue, B.strValue)); B.pEnum = PersonEnum.EnumB; Write( string .Format( " Enum->[A:{0}] [B:{1}] " , ( int )A.pEnum, ( int )B.pEnum)); B.pStruct.StructValue = 2 ; Write( string .Format( " struct->[A:{0}] [B:{1}] " , A.pStruct.StructValue, B.pStruct.StructValue)); B.pIntArray[ 0 ] = 2 ; Write( string .Format( " intArray->[A:{0}] [B:{1}] " , A.pIntArray[ 0 ], B.pIntArray[ 0 ])); B.pStringArray[ 0 ] = " 2 " ; Write( string .Format( " stringArray->[A:{0}] [B:{1}] " , A.pStringArray[ 0 ], B.pStringArray[ 0 ])); B.pClass.Name = " 2 " ; Write( string .Format( " Class->[A:{0}] [B:{1}] " , A.pClass.Name, B.pClass.Name)); System.Console.Read(); } static void Write( string msg) { System.Console.WriteLine(msg); } 说明:
我们通过改变B实例的值,然后打印出A和B的值看结果。
打印结果如下:
![](http://images.cnblogs.com/cnblogs_com/cyq1162/201009/copy_demo_1.jpg)
从最后输出的结果我们得知:
对于内部的Class的对象和数组,会Copy地址一份。[从而改变B时,A也被改变了] 而对于其它内置的int/string/Enum/struct/object类型,则进行值copy。
最后,我试着百度寻找浅拷贝最原生的定义,浅搜了一下找不到,那这个定义,就留给读者解答一下了。
接着,我顺手比较了一下浅拷贝和深拷贝的性能测试:
先在DemoClass加入一个函数:
public object CloneNew() { return new DemoClass(); }
接着我们写示例代码比较:
public static void Compare() { DemoClass baseClass = new DemoClass(); DateTime start = DateTime.Now; for ( int i = 0 ; i < 1000000 ; i ++ ) { DemoClass newClass = (DemoClass)baseClass.Clone(); } TimeSpan ts = DateTime.Now - start; System.Console.WriteLine( " 浅拷贝: " + ts.Ticks); DateTime start2 = DateTime.Now; for ( int j = 0 ; j < 1000000 ; j ++ ) { DemoClass newClass = (DemoClass)baseClass.CloneNew(); } TimeSpan ts2 = DateTime.Now - start2; System.Console.WriteLine( " 深拷贝: " + ts2.Ticks); System.Console.Read(); }
最后得出结果:
![](http://images.cnblogs.com/cnblogs_com/cyq1162/201009/copy_demo_2.jpg)
看来直接用浅拷贝性能还不如直接返回一个new的对象。 同样的,用克隆返回object最后还得对类型转换进行一些开销,教人情何以堪!
附言:
这两天刚好感冒,插了这两篇解惑篇,都是临时插进来的的问题了,接下来会继续写 框架 的相关文章。
转载地址:http://hsrel.baihongyu.com/