C# 浅拷贝与深拷贝区别 解惑篇

简介:

问题起源:

昨天被同事问到一个浅拷贝与深拷贝区别的问题,说实在的,记得在学校时在书在看过相关概念区别。
只是,那时的在校生,又有几个能对书本上那写的尽量让鬼都看不懂知识能清晰的理解呢。
工作后虽然也有用到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
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的值看结果。

 

打印结果如下:

从最后输出的结果我们得知:

对于内部的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();
        }
复制代码

 

最后得出结果:

看来直接用浅拷贝性能还不如直接返回一个new的对象。
同样的,用克隆返回object最后还得对类型转换进行一些开销,教人情何以堪!

 

附言:

这两天刚好感冒,插了这两篇解惑篇,都是临时插进来的的问题了,接下来会继续写 CYQ.Data 轻量数据层之路 框架 的相关文章。

 

 

版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:

http://www.cnblogs.com/cyq1162/archive/2010/09/05/1818413.html

相关文章
|
7月前
|
C#
C#学习相关系列之yield和return的区别
C#学习相关系列之yield和return的区别
126 1
|
7月前
|
C#
C#系列之ref和out的区别
C#系列之ref和out的区别
252 0
|
1月前
|
Java 物联网 编译器
C#一分钟浅谈:.NET Core 与 .NET 5 区别
本文对比了 .NET Core 和 .NET 5,从历史背景、主要区别、常见问题及易错点等方面进行了详细分析。.NET Core 侧重跨平台支持和高性能,而 .NET 5 在此基础上统一了 .NET 生态系统,增加了更多新特性和优化。开发者可根据具体需求选择合适的版本。
51 7
|
6月前
|
存储 安全 Java
程序与技术分享:C#值类型和引用类型的区别
程序与技术分享:C#值类型和引用类型的区别
50 0
|
2月前
|
网络协议 网络性能优化 C#
C# 一分钟浅谈:UDP 与 TCP 协议区别
【10月更文挑战第8天】在网络编程中,传输层协议的选择对应用程序的性能和可靠性至关重要。本文介绍了 TCP 和 UDP 两种常用协议的基础概念、区别及应用场景,并通过 C# 代码示例详细说明了如何处理常见的问题和易错点。TCP 适用于需要可靠传输和顺序保证的场景,而 UDP 适用于对延迟敏感且可以容忍一定数据丢失的实时应用。
52 1
|
1月前
|
开发框架 安全 .NET
C#面:Server.UrlEncode、HttpUtility.UrlDecode的区别
通过上述详细的解释和实例分析,相信大家对 `Server.UrlEncode` 和 `HttpUtility.UrlDecode` 的区别有了更深刻的理解,并能在实际开发中灵活运用。
43 0
|
2月前
|
C# 开发者
【捞底干货】C#中equals和==运算符的区别
【捞底干货】C#中equals和==运算符的区别
86 1
|
3月前
|
C# 索引
C# 一分钟浅谈:接口与抽象类的区别及使用
【9月更文挑战第2天】本文详细对比了面向对象编程中接口与抽象类的概念及区别。接口定义了行为规范,强制实现类提供具体实现;抽象类则既能定义抽象方法也能提供具体实现。文章通过具体示例介绍了如何使用接口和抽象类,并探讨了其实现方式、继承限制及实例化差异。最后总结了选择接口或抽象类应基于具体设计需求。掌握这两者有助于编写高质量的面向对象程序。
140 5
|
4月前
|
C#
C#中的overload,overwrite,override的语义区别
以上概念是面向对象编程中实现多态性和继承的重要基石。理解它们之间的区别对于编写清晰、可维护的代码至关重要。
148 7
|
7月前
|
C#
c#一文读懂continue、return、break区别
c#一文读懂continue、return、break区别
62 0