Preface

We have learned the design pattern before, in which we have learned the prototype pattern. This involves cloning your own objects. That is to copy the object. This involves such a concept. What is a deep copy and what is a shallow copy? Let’s have a look.

Shallow copy

First let’s look at the light copy. Shallow copy is to copy all fields in an object to a new object. Shallow copy has different effects on value type and reference type. When a value of type value is copied to the replica, changing the value in the replica does not affect the value of the original object. However, what the reference type is copied to the replica is the reference of the reference type. Is not a referenced object. In this way, changing the value in the copy will cause the value of the original object to be changed. But here we need to exclude strings for reference typesString type.

So why does the reference type change the value of the copy to change the value of the original objectString string type is excluded? First of all, we need to know the concept that string type is an immutable data type, which means that the string object can not be changed after initialization. On the surface, the method and operation of modifying the content of the string is actually to create a new string, and then copy the content of the old string to the new string as needed. How to understand you? Let’s look at the following case:

#Region string comparison
        /// 
        ///Get memory address method of reference type
        /// 
        /// 
        /// 
        public static string getMemory(object o)
        {
            GCHandle h = GCHandle.Alloc(o, GCHandleType.Pinned);
            IntPtr addr = h.AddrOfPinnedObject();
            return "0x" + addr.ToString("X");
        }
        /// 
        ///String comparison
        /// 
        public static void Compares()
        {
            string a = "123";
            Console. Writeline ("reference address of a: \ t \ T" + getmemory (a));
            string b = "123";
            Console. Writeline ("B's reference address: \ t \ T" + getmemory (b));
            Console. Writeline ("comparison between a and B: \ t \ T" + object. Referenceequals (a, b));
            b = "456";
            Console. Writeline ("B's reference address: \ t \ T" + getmemory (b));


        }

        #endregion

Here we seea=”123”,b=”123”。 We see that their reference addresses are the same. That is to say, let’s createA creates the string a and has a reference address. Then when we create B, we first look for the same value. If the same value exists, get its reference address. That’s why the reference addresses of a and B are the same. This involves something called character resident pool. The string is saved. Then we modify the value of B and output its reference address, which is different from the previous reference address. The description is not to modify the original value, but to recreate a string and retrieve its reference address.

Let’s look at a shallow copy case. First, we prepare the values of the following data types:int,string,enum,struct,class,int[],string[]。

/// 
    // / enumeration
    /// 
    public enum EnumTest
    {
        TestOne = 1,
        TestTwo = 2
    }

    /// 
    ///Structure
    /// 
    public struct StructTest
    {
        public int Test;
        public StructTest(int i)
        {
            Test = i;
        }
    }

    /// 
    // / class
    /// 
    public class ClassTest
    {
        public string TestString;
        public ClassTest(string _string)
        {
            TestString = _string;
        }
    }
    /// 
    ///Deep copy
    /// 
    public class DeepClone : ICloneable
    {
        public int _int = 1;
        public string _string = "1";
        public EnumTest _enum = EnumTest.TestOne;
        public StructTest _struct = new StructTest(1);
        public ClassTest _class = new ClassTest("1");
        public int[] arrInt = new int[] { 1 };
        public string[] arrString = new string[] { "1" };
        public object Clone()
        {
            var NewOne = JsonConvert.SerializeObject(this);
            return JsonConvert.DeserializeObject(NewOne);
        } 
    }
    class Program
    {
        static void Main(string[] args)
        {
            DeepClone simple = new DeepClone();
            var simpleTwo = (DeepClone)simple.Clone();
            simpleTwo._int = 2;
            simpleTwo._string = "2";
            simpleTwo._enum = EnumTest.TestTwo;
            simpleTwo._struct.Test = 2;
            simpleTwo._class.TestString = "2";
            simpleTwo.arrInt[0] = 2;
            simpleTwo.arrString[0] = "2";

            Console. Writeline ($"int type change original object: {simple. _int} \ t \ tbackup object: {simpletwo. _int}");
            Console. Writeline ($"string type change original object: {simple. _string} \ t \ tbackup object: {simpletwo. _string}");
            Console. Writeline ($"enum type change original object: {(int) simple. ﹣ enum} \ t \ tbackup object: {(int) simpletwo. ﹣ enum}");
            Console. Writeline ($"struct type change original object: {simple. Struct. Test} \ t \ tbackup object: {simpletwo. Struct. Test}");
            Console. Writeline ($"class type change original object: {simple. _class. Teststring} \ t \ tbackup object: {simpletwo. _class. Teststring}");
            Console. Writeline ($"int array type change original object: {simple. Arrint [0]} \ t \ tbackup object: {simpletwo. Arrint [0]}");
            Console. Writeline ($"string array type change original object: {simple. Arrstring [0]} \ t \ tbackup object: {simpletwo. Arrstring [0]}");
        } 
    }

We inheritThe icloneable interface makes shallow copies of these types and then modifies the replica object. Output the original object and the copy object for comparison. We found that the original object values of int, enum, struct, value type and string, the special reference type, were not changed. But class, int [], string [], the original object of reference type object has been affected to change the value. It also verifies what we said before. Shallow copy is to assign an object to a copy object. The value type copies the value, and the reference type copies its reference object. Modify the value of the replica object, the value type and the original string object will not be affected, and the reference type will be affected except for the original string object.

Deep copy

We saw the shallow copy above. The shallow copy still has some influence. If we can’t deal with it well, it will be possibleBug. So let’s see what the corresponding deep copy looks like? It can be declared that the deep copy does not discriminate between value type and reference type. Deep copy also copies all fields in the object to the new object, but the object will be recreated and then copied to the replica object, regardless of value type or reference type. Changes to the replica object will not affect the original object, regardless of type.

Let’s continue to make a deep copy of the above example:

/// 
    ///Deep copy
    /// 
    public class DeepClone : ICloneable
    {
        public int _int = 1;
        public string _string = "1";
        public EnumTest _enum = EnumTest.TestOne;
        public StructTest _struct = new StructTest(1);
        public ClassTest _class = new ClassTest("1");
        public int[] arrInt = new int[] { 1 };
        public string[] arrString = new string[] { "1" };
        public object Clone()
        {
            var NewOne = JsonConvert.SerializeObject(this);
            return JsonConvert.DeserializeObject(NewOne);
        } 
    }

    class Program
    {
        static void Main(string[] args)
        {
            DeepClone simple = new DeepClone();
            var simpleTwo = (DeepClone)simple.Clone();
            simpleTwo._int = 2;
            simpleTwo._string = "2";
            simpleTwo._enum = EnumTest.TestTwo;
            simpleTwo._struct.Test = 2;
            simpleTwo._class.TestString = "2";
            simpleTwo.arrInt[0] = 2;
            simpleTwo.arrString[0] = "2";

            Console. Writeline ($"int type change original object: {simple. _int} \ t \ tbackup object: {simpletwo. _int}");
            Console. Writeline ($"string type change original object: {simple. _string} \ t \ tbackup object: {simpletwo. _string}");
            Console. Writeline ($"enum type change original object: {(int) simple. ﹣ enum} \ t \ tbackup object: {(int) simpletwo. ﹣ enum}");
            Console. Writeline ($"struct type change original object: {simple. Struct. Test} \ t \ tbackup object: {simpletwo. Struct. Test}");
            Console. Writeline ($"class type change original object: {simple. _class. Teststring} \ t \ tbackup object: {simpletwo. _class. Teststring}");
            Console. Writeline ($"int array type change original object: {simple. Arrint [0]} \ t \ tbackup object: {simpletwo. Arrint [0]}");
            Console. Writeline ($"string array type change original object: {simple. Arrstring [0]} \ t \ tbackup object: {simpletwo. Arrstring [0]}");
        } 
    }

Here we see the running result. No matter the value type or the reference type, the value of the original object will not be affected after the replica object is modified. This is the characteristic of deep copy.

 

summary

We’ve seen the shallow copy and the deep copy. Let’s review them carefully.The shallow copy copies the object’s fields to the new object, but when the new object is modified, the value type andA field of type string will not affect the field of the original object, while a reference type will affect the value of the original object except for the string type. Deep copy also copies the field of the object to the new object, but the change of value type or reference type will not affect the value of the original object. Because the deep copy is to recreate the original object and then copy it to the replica object.


  Life is only beautiful, not brilliant.

Welcome to scan the QR code below and learn more with me