Shallow copy and deep copy in depth understanding of of shallow copy VS deep copy

  • 2020-06-03 08:06:02
  • OfStack

The introduction
There are two types of variables in C#, one is a value type variable and the other is a reference type variable. For a value type variable, both the deep copy and the previous copy are implemented using the assignment symbol (=), which has the effect of 1, copying the value type fields from the object into the new object. This is easy to understand. This article focuses on the copying mechanism and implementation of reference type variables.

There are two copy operations in C# that refer to objects of type:

The & # 8226; Shallow copy (shadow clone /shallow copy): Only copy the value type field of the object, the reference type of the object, still belongs to the original reference.
The & # 8226; Deep copy (deep clone): Copies not only the value type fields of the object, but also the objects in the original object.

The difference between a shallow copy and a deep copy: a shallow copy is copying a numeric field from an object to a new object, while a reference field in an object is copying one of its references to the target object.

Note: The string type is a bit special, and for shallow copies, class value type objects are handled.

Implementation of shallow copy
1. Implementation using Object class MemberwiseClone
MemberwiseClone: Creates a shallow copy of the current Object.
The MemberwiseClone method creates a copy of the shallow table by creating a new object and then copying the non-static fields of the current object to the new object. If the field is of value type, the field is copied bit by bit. If the field is a reference type, copy the reference but not the referenced object; Therefore, the original object and its duplicate reference are the same as the 1 object.

The code implementation is as follows:


public class Person
    {
        public int Age { get; set; }
        public string Address { get; set; }
        public Name Name { get; set; }
        public object Clone()
        {
           return   this.MemberwiseClone();    
        }
        
    }

    public class Name
    {
        public Name(string frisName,string lastName)
        {
            FristName = frisName;
            LastName = lastName;
        }
        public string FristName { get; set; }
        public string LastName { get; set; }
    }

2. Assignment (=)VS is implemented using the Object class MemberwiseClone
There is a misconception that an assignment is a shallow copy of a variable of reference type, but it is not.

1. The shallow copy (shallow copy) copies the value type fields in the reference type object bit by bit. The assignment operator simply assigns a reference to the source object to the destination object, both referring to the same object.

2. Changes in value type fields of objects after shallow copying will not be reflected in source objects, while changes in value type fields of objects after assignment will be reflected in source objects

The code implementation is as follows:


public class Person
    {
        public int Age { get; set; }
        public string Address { get; set; }
        public Name Name { get; set; }
    }

    public class Name
    {
        public Name(string frisName,string lastName)
        {
            FristName = frisName;
            LastName = lastName;
        }
        public string FristName { get; set; }
        public string LastName { get; set; }
    }

Deep copy implementation
Instead of a shallow copy, a new object is created according to the prototype of the source object, and all fields of the current object are copied bit by bit and recursively supported, whether of value type or reference type, static or non-static.
In C#, we have three ways to implement deep copy

1. Implement ICloneable interface and customize copy function.

The ICloneable interface, which supports cloning, creates a new instance of a class with the same value as an existing instance.

The ICloneable interface contains one member, Clone, which is used to support clones other than those provided by MemberwiseClone. Clone can be implemented as either a deep copy or a shallow copy. In a deep copy, all objects are duplicated; In a shallow copy, only top-level objects are duplicated, and objects below the top-level contain references. The resulting clone must have the same type as the original instance or the compatible type of the original instance.

The code implementation is as follows:


 public class Person:ICloneable
    {
        public int Age { get; set; }
        public string Address { get; set; }
        public Name Name { get; set; }
        public object Clone()
        {
            Person tem = new Person();
            tem.Address = this.Address;
            tem.Age = this.Age;
            tem.Name = new Name(this.Name.FristName, this.Name.LastName);
            return tem;
        }
    }

    public class Name
    {
        public Name(string frisName, string lastName)
        {
            FristName = frisName;
            LastName = lastName;
        }
        public string FristName { get; set; }
        public string LastName { get; set; }
    }

As you can see, the Person class inherits the interface ICloneable and manually implements its Clone method. This is a simple class. Imagine if your class had thousands of reference type members (too much, of course, 10 or so).

2. Serialization/deserialization class implementation

I don't know if you've noticed the DataSet object, but it offers two methods:

The ES77en. Clone approach replicates the structure of DataSet, including all DataTable architectures, relationships, and constraints. Do not copy any data.

The new DataSet has the same architecture as the current DataSet, but does not contain any data. Note that if subclasses of these classes have been created, the copy will also belong to the same subclass.

The DataSet. Copy method copies the structure and data of the DataSet.

The new DataSet has the same structure (table schema, relationships, and constraints) and data as the DataSet. Note that if subclasses of these classes have been created, the copy will also belong to the same subclass.

It seems to be neither a shallow copy nor a deep copy. Are you disappointed? But isn't the combination the deep copy we want? Looking at the implementation of DataSet, note the serialization interface: ISerializable

Serialization is the process of converting an object or object graph into a linear sequence of bytes for storage or transfer to another location. Deserialization is the process of taking the stored information and using it to recreate the object.

Through the ISerializable interface, classes can perform their own serialization behavior.

Is the process of converting to a linear sequence of bytes and using it to recreate an object much like our deep copy meaning "bit by bit"?

The code implementation is as follows:


[Serializable]
    public class Person : ICloneable
    {
        public int Age { get; set; }
        public string Address { get; set; }
        public Name Name { get; set; }
        public object Clone()
        {
            using (MemoryStream ms = new MemoryStream(1000))
            {
                object CloneObject;
                BinaryFormatter bf = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.Clone));
                bf.Serialize(ms, this);
                ms.Seek(0, SeekOrigin.Begin);
                //  Deserialize to another 1 Object (that is, created 1 A deep copy of the original object) 
                CloneObject = bf.Deserialize(ms);
                //  Close the stream  
                ms.Close();
                return CloneObject;
            }
        }
    }

    [Serializable]
    public class Name
    {
        public Name(string frisName, string lastName)
        {
            FristName = frisName;
            LastName = lastName;
        }
        public string FristName { get; set; }
        public string LastName { get; set; }
    }
}

Note: Deep copy is implemented through serialization and deserialization, and its and its field types must be marked as serializable, which adds features (Attribute)[Serializable].

3. Through reflection
By serialization/deserialization we can achieve a smooth deep copy, but when it comes to IO operations, IO operations consume resources in a managed environment. Could there be a more elegant solution? CreateInstance, right, using reflective properties. This method you can refer to this blog: http: / / rubenhak com /? p=70 article reflection class Attribute, using ES123en.CreateInstance New1 class out (a bit like ES126en.Clone to get the architecture first), and then using PropertyInfo SetValue and GetValue methods, traversal way to fill the value.

The code implementation is as follows:


public class Person
{
    private List<Person> _friends = new List<Person>();
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    [Cloneable(CloneableState.Exclude)]
    [Cloneable(CloneableState.Include, "Friends")]
    public List<Person> Friends { get { return _friends; } }
    [Cloneable(CloneableState.Exclude)]
    public PersonManager Manager { get; set; }
}

C# Why design deep and shallow copies?
This I also 1 straight also can't find 1 suitable answer, hope someone to discuss next! Click to download the code


Related articles: