为了账号安全,请及时绑定邮箱和手机立即绑定

C# 浅拷贝与深拷贝的区别

标签:
C#

一年多以前,我去面试,被一个人问到浅拷贝与深拷贝区别,我答:浅拷贝就是拷贝就是拷贝架构,不包括值,深拷贝就是连值也一同拷贝。

当我答出这样错误的答案时,对方没有纠正,反而似乎对我的答案还挺满意的。
唉,面试管自己不懂还问我这问题,还让我一直以为到现在都是这个样。

同事的质问:

接着同事说它的示例里,发现值是有拷贝的,于是我意识到我的认知是有问题了,我重新百度了一下。
网上乱七杂八的答案,让我得一个模糊的似乎正确的答案:浅拷贝不拷贝内部类的对象

引申出的错乱:

接着同事的疑问更一度把我引向这个容易迷乱的错误深渊:浅拷贝是对引用类型拷贝地址,对值类型直接进行拷贝。

 

最后,为了解惑,还是用示例来说话了:

    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
stringint[]
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的值看结果。

 

打印结果如下:

https://img1.sycdn.imooc.com//5af3e2260001cd6e02560165.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();
        }

 

最后得出结果:

https://img1.sycdn.imooc.com//5af3e24c00016cd702220077.jpg

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

 

 

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消