C# clone

The clone method is a must in the prototyping pattern, it will return an object consistent with the current object data. As the name suggests, it is carved out of a mold. There are two types of clones: shallow clone and deep clone.

1. Shallow clone

Shallow clone method is the simplest and most direct method. It is only necessary for the class to implement the Clone method of the interface ICloneable (under the namespace System.Runtime.InteropServices), and use the MemberwiseClone() method added to the current class in the method. Such as:

public class Student:ICloneable
{
    ///  <summary> 
    /// Value type
     ///  </summary> 
    public  int ID { get ; set ; } ///  <summary> 
    /// Reference type
     ///  </summary> 
    public  object obj { get ; set ; }

    public object Clone()
    {
        return this.MemberwiseClone();
    }
}

The above method implements a shallow clone of the class object. But there is a reference type field in this class, the shallow clone method cannot clone the reference field, the reference field is just an address reference to it. Therefore, when the data of the reference field of the original or copy is modified, the data of the reference object of another object will also change. Deep cloning will effectively solve this problem.

2. Deep clone

Deep cloning is more complicated than shallow cloning. The mechanism implemented by deep cloning is to serialize the object into data, and then deserialize the data into a new object again. It needs to be marked as serializable above the class before implementing serialization. The serialization method used in this paper is binary serialization. The main implementation code is as follows:

[Serializable] // Mark feature: serializable 
 public  class Student : ICloneable
 {
     ///  <summary> 
     /// Value type
      ///  </summary> 
     public  int ID { get ; set ; }
      ///  <summary> 
     /// Reference type
      ///  </summary> 
     public  object obj { get ; set ; } 
public Student Clone() { Student clone = new Student(); // Serialize where to write the file using (FileStream fs = new FileStream( " temp.dat " , FileMode.OpenOrCreate)) { BinaryFormatter formatter = new BinaryFormatter(); try { formatter.Serialize(fs, this);//序列化 } catch (SerializationException e) { Console.WriteLine("Failed to serialize. Reason: " + e.Message); throw; } finally { fs.Close(); } } // Deserialize the location of the read data (note: the data reference here should be consistent with the serialized file name) using (FileStream fs1 = new FileStream( " temp.dat " , FileMode.Open)) { BinaryFormatter formatter1 = new BinaryFormatter(); try { clone = formatter1.Deserialize(fs1) as Student; // Deserialize the data and parse it into the corresponding type } catch (SerializationException e) { Console.WriteLine("Failed to deserialize. Reason: " + e.Message); throw; } finally { fs1.Close(); } } return clone; } }

The implementation mechanism of deep cloning is relatively complicated and the efficiency is slightly slower, but it overcomes the shortcomings of shallow cloning, so that when cloning objects, the reference type data in the class is completely cloned into a new object instead of referencing the original object. In this way, it will not interfere with the other party when modifying the data of the reference type object of both parties.

But implementing the clone method for each class, and writing the same code over and over again, is a hassle. Hence the introduction of generic methods.

3. Generic method to achieve cloning

The emergence of generics makes it a good solution to the trouble of repeatedly writing code when multiple classes or structures need to be cloned. Only need to use the relevant method externally. Its code is as follows:

public class Clone
{
    /// <summary>
    /// 深克隆
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="t"></param>
    /// <returns></returns>
    public static T DepthClone<T>(T t)
    {
        T clone = default (T);
         // Serialize where to write to the file 
        using (FileStream fs = new FileStream( " temp.dat " , FileMode.OpenOrCreate))
        {
            BinaryFormatter formatter = new BinaryFormatter();
            try
            {
                formatter.Serialize(fs, t);//序列化
            }
            catch (SerializationException e)
            {
                Console.WriteLine("Failed to serialize. Reason: " + e.Message);
                throw;
            }
            finally
            {
                fs.Close();
            }
        }
        // Deserialize the location of the read data (note: the data reference here should be consistent with the serialized file name) 
        using (FileStream fs1 = new FileStream( " temp.dat " , FileMode.Open))
        {
            BinaryFormatter formatter1 = new BinaryFormatter();
            try
            {
                clone = (T)formatter1.Deserialize(fs1); // Deserialize the data and parse it into the corresponding type 
            }
             catch (SerializationException e)
            {
                Console.WriteLine("Failed to deserialize. Reason: " + e.Message);
                throw;
            }
            finally
            {
                fs1.Close();
            }
        }
        return clone;
    }
}

The method used externally is as follows:

Student stu1 = new Student(); // instantiate an object 
 stu1.obj = new  object (); // instantiate the reference object in the object 
 Student stu2 = Clone.DepthClone(stu1); // deep clone the object

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326462386&siteId=291194637