zoukankan      html  css  js  c++  java
  • 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 轻量数据层之路 框架 的相关文章。
    版权声明:本文原创发表于 博客园,作者为 路过秋天 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
    个人微信公众号
    创业QQ群:617713515
    Donation(扫码支持作者):支付宝:
    Donation(扫码支持作者):微信:
  • 相关阅读:
    Apple Watch知识点总结
    segue场景跳转的使用总结
    iOS地图相关知识点总结
    第三方库AFNetwork的作用和用法详解
    UIImagePickerController的知识点总结
    关于图片的压缩问题
    盒子模型知识
    CSS3新增属性
    ps命令详解
    http请求中的Referer的作用
  • 原文地址:https://www.cnblogs.com/cyq1162/p/1818413.html
Copyright © 2011-2022 走看看