1. 程式人生 > >C# 淺克隆與深克隆

C# 淺克隆與深克隆

一、淺克隆:

     在淺克隆中,如果原型物件的成員變數是值型別,將複製一份給克隆物件;如果原型物件的成員變數是引用型別,則將引用物件的地址複製一份給克隆物件,也就是說原型物件和克隆物件的成員變數指向相同的記憶體地址。簡單來說,在淺克隆中,當物件被複制時只複製它本身和其中包含的值型別的成員變數,而引用型別的成員物件並沒有複製,如圖:

在C#中,通過實現ICloneable介面的Clone方法()呼叫MemberwiseClone方法)來實現淺克隆:

    public class WeeklyLog:ICloneable
    {
        public string Name { get; set; }
        public Student Student { get; set; }

        public object Clone()
        {
            return this.MemberwiseClone();
        }
    }
    {
        public string Address { get; set; }
    }
    static void Main(string[] args)
        {
            WeeklyLog log1 = new ProtoTypeTest.WeeklyLog();
            log1.Name = "log1";
            log1.Student = new ProtoTypeTest.Student() { Address = "haidian" };

            WeeklyLog log2 = (WeeklyLog)log1.Clone();//呼叫淺克隆方法
            Console.WriteLine(log1.Name);//log1
            Console.WriteLine(log2.Name);//log1
            Console.WriteLine(log1.Student.Address);//haidian
            Console.WriteLine(log2.Student.Address);//haidian
            Console.WriteLine(object.ReferenceEquals(log1, log2));//false
            log2.Name = "log2";//修改克隆的物件的name屬性
            Console.WriteLine(log1.Name);//log1
            Console.WriteLine(log2.Name);//log2
            log2.Student.Address = "chaoyang";//修改克隆的物件的引用型別Student的Address屬性
            Console.WriteLine(log1.Student.Address);//chaoyang
            Console.WriteLine(log2.Student.Address);//chaoyang
            Console.ReadLine();

        }

二、深克隆:

     在深克隆中,無論原型物件的成員變數是值型別還是引用型別,都將複製一份給克隆物件,深克隆將原型物件的所有引用物件也複製一份給克隆物件。簡單來說,在深克隆中,除了物件本身被複制外,物件所包含的所有成員變數也將複製,如圖:

    在C#語言中,如果需要實現深克隆,可以通過序列化(Serialization)等方式來實現。序列化就是將物件寫到流的過程,寫到流中的物件是原有物件的一個拷貝,而原物件仍然存在於記憶體中。通過序列化實現的拷貝不僅可以複製物件本身,而且可以複製其引用的成員物件,因此通過序列化將物件寫到一個流中,再從流裡將其讀出來,可以實現深克隆。需要注意的是能夠實現序列化的物件其類必須實現Serializable介面,否則無法實現序列化操作。下面我們使用深克隆技術來實現工作週報和附件物件的複製,由於要將附件物件和工作週報物件都寫入流中,因此兩個類用Serializable標識可序列化:

 [Serializable]
    public class WeeklyLog
    {
        public string Name { get; set; }
        public Student Student { get; set; }

        public WeeklyLog DeepClone()
        {
            object obj = null;
            //將物件序列化成記憶體中的二進位制流
            BinaryFormatter inputFormatter = new BinaryFormatter();
            MemoryStream inputStream;
            using (inputStream = new MemoryStream())
            {
                inputFormatter.Serialize(inputStream, this);
            }
            //將二進位制流反序列化為物件
            using (MemoryStream outputStream = new MemoryStream(inputStream.ToArray()))
            {
                BinaryFormatter outputFormatter = new BinaryFormatter();
                obj = outputFormatter.Deserialize(outputStream);
            }
            return (WeeklyLog)obj;
        }

    }

    [Serializable]
    public class Student
    {
        public string Address { get; set; }

    }
<pre name="code" class="csharp">    static void Main(string[] args)
        {
            WeeklyLog log1 = new ProtoTypeTest.WeeklyLog();
            log1.Name = "log1";
            log1.Student = new ProtoTypeTest.Student() { Address = "haidian" };

            WeeklyLog log2 = (WeeklyLog)log1.DeepClone();//呼叫深克隆方法
            Console.WriteLine(log1.Name);//log1
            Console.WriteLine(log2.Name);//log1
            Console.WriteLine(log1.Student.Address);//haidian
            Console.WriteLine(log2.Student.Address);//haidian
            Console.WriteLine(object.ReferenceEquals(log1, log2));//false
            log2.Name = "log2";//修改克隆的物件的name屬性
            Console.WriteLine(log1.Name);//log1
            Console.WriteLine(log2.Name);//log2
            log2.Student.Address = "chaoyang";//修改克隆的物件的引用型別Student的Address屬性
            Console.WriteLine(log1.Student.Address);//haidian
            Console.WriteLine(log2.Student.Address);//chaoyang
            Console.ReadLine();

        }