深拷贝和浅拷贝的区别

时间:2021-09-05 19:50:21

 

浅拷贝一般是用的这个方法  MemberwiseClone()

在拷贝的时候主要是关心值和引用两者拷贝后的区别,这个区别也是深拷贝和浅拷贝的区别


下面这个类中就使用了这个方法


         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最后还得对类型转换进行一些开销,教人情何以堪!