C# List的深復制


1、關於深拷貝和淺拷貝

C#支持兩種類型:值類型和引用類型

值類型(Value Type):如 char, int, float,枚舉類型和結構類型

引用類型(Reference Type):如Class類型、接口類型、委托類型、數組類型。

如何來划分它們?

以它們在計算機內存中如何分配來划分。

堆棧(Stack)是一種先進先出的數據結構,在內存中,變量會被分配在堆棧上來進行操作。

堆(Heap)是用於為類型實例(對象)分配空間的內存區域,在堆上創建一個對象,會將對象的地址傳遞給堆棧上的變量(反過來叫變量指向此對象,或者變量引用此對象)。

值類型與引用類型的區別?

(1)、值類型的變量直接包含其數據

(2)、引用類型的變量則存儲對象引用

對於引用類型,兩個變量可能引用同一個對象,因此對一個變量的操作可能影響到另一個變量所引用的對象。

對於值類型,每個變量都有自己的數據副本,對於一個變量的操作不可能影響到另一個變量。

值類型隱式繼承自System.ValueType,所以不能顯示讓一個結構繼承一個類,C#不支持多繼承。 

關於對象克隆的所設計到知識點

淺拷貝:是指將對象中的所有字段逐字復制到一個新對象

對值類型字段只是簡單的拷貝一個副本到目標對象,改變目標對象中值類型字段的值不會反映到原始對象中,因為拷貝的是副本。實現淺拷貝需要使用Object類的MemberwiseClose方法用於創建一個淺表副本。

對引用類型字段則是指拷貝他的一個引用到目標對象,改變目標對象中引用類型字段的值會將它反映到原始對象中,因為拷貝的是指向堆是上的一個地址。

深拷貝:深拷貝與淺拷貝不同的是對於引用字段的處理,深拷貝會將在新對象中創建一個新的對象和原始對象字段相同(內容相同)的字段,也就是說這個引用和原始對象引用是不同,我們改變新對象這中這個字段的時候是不會影響到原始對象中對應字段的內容。須實現ICloneable接口中的Clone方法,且需要將被克隆對象加上[Serializable]特性。

引用類型的賦值、淺拷貝和深拷貝的區別

賦值:就是將原來對象的地址給新的對象拷貝一下即可。

淺拷貝:需要繼承ICloneable接口(支持克隆,即用現有實例相同的值創建類的新實例),然后用MemberwiseClone方法(創建當前System.Object的淺表對象)。但是需要注意的是MemberwiseClone拷貝方式,首先它是淺拷貝,方法是將所有的值類型字段拷貝一個副本,但是引用類型不會創建副本,僅僅是傳遞一個相同的地址給新對象,並且新對象和原對象指向的地址是一致的,這里有個問題就是string類型,但是實際上卻是和值類型表現一致。

深拷貝:深拷貝與淺拷貝不同的是對於引用字段的處理,深拷貝會將在新對象中創建一個新的對象和原始對象字段相同(內容相同)的字段,也就是說這個引用和原始對象引用是不同,我們改變新對象這中這個字段的時候是不會影響到原始對象中對應字段的內容。須實現ICloneable接口中的Clone方法,且需要將被克隆對象加上[Serializable]特性。

2 List 的深拷貝

代碼如下:

    /// <summary>
    /// Class Program
    /// </summary>
    class Program
    {
        /// <summary>
        /// Defines the entry point of the application.
        /// </summary>
        /// <param name="args">The args.</param>
        static void Main(string[] args)
        {
            List<Person> originalList = new List<Person>();
            Person person = new Person();
            person.Name = "zhangsan";
            person.Age = 90;
            Job job = new Job();
            job.JobName = "開發工程師";
            person.PersonJob = job;
            originalList.Add(person);

            person = new Person();
            person.Name = "lisi2";
            job = new Job();
            job.JobName = "開發工程師";
            person.PersonJob = job;
            originalList.Add(person);

            person = new Person();
            person.Name = "3";
            job = new Job();
            job.JobName = "測試工程師";
            person.PersonJob = job;
            originalList.Add(person);

            Console.WriteLine("原數據如下:");
            for (int i = 0; i < originalList.Count; i++)
            {
                Console.WriteLine("Name:" + originalList[i].Name + ",JobName:" + originalList[i].PersonJob.JobName);
            }

            Console.WriteLine("--------------List深復制------------------");
            List<Person> deepCopyList = Clone<Person>(originalList);
            deepCopyList[1].Name = "lisi";
            for (int i = 0; i < originalList.Count; i++)
            {
                Console.WriteLine("原數據:Name:" + originalList[i].Name + ",JobName:" + originalList[i].PersonJob.JobName);
                Console.WriteLine("深復制后:Name:" + deepCopyList[i].Name + ",JobName:" + deepCopyList[i].PersonJob.JobName);
            }

            Console.WriteLine("----------------List賦值----------------");
            List<Person> shallowCopyList = originalList;
            shallowCopyList[2].Name = "amy";
            shallowCopyList[2].PersonJob.JobName = "產品工程師";
            Job modifyJob = new Job();
            modifyJob.JobName = "UNKNOWN";
            shallowCopyList[1].PersonJob = modifyJob;
            for (int i = 0; i < originalList.Count; i++)
            {
                Console.WriteLine("原數據:Name:" + originalList[i].Name + ",JobName:" + originalList[i].PersonJob.JobName);
                Console.WriteLine("淺復制:Name:" + shallowCopyList[i].Name + ",JobName:" + shallowCopyList[i].PersonJob.JobName);
            }

            Console.Read();
        }

        /// <summary>
        /// Clones the specified list.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="List">The list.</param>
        /// <returns>List{``0}.</returns>
        public static List<T> Clone<T>(object List)
        {
            using (Stream objectStream = new MemoryStream())
            {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, List);
                objectStream.Seek(0, SeekOrigin.Begin);
                return formatter.Deserialize(objectStream) as List<T>;
            }
        }
    }

兩個測試類代碼如下:

/// <summary>
    /// Class Person
    /// </summary>
    [Serializable]
    public class Person 
    {
        /// <summary>
        /// Gets or sets the person job.
        /// </summary>
        /// <value>The person job.</value>
        public Job PersonJob
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the age.
        /// </summary>
        /// <value>The age.</value>
        public int Age
        {
            get;
            set;
        }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns>System.Object.</returns>
        public object Clone()
        {
            BinaryFormatter formatter = new BinaryFormatter(null, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Clone));
            MemoryStream stream = new MemoryStream();
            formatter.Serialize(stream, this);
            stream.Position = 0;
            object clonedObj = formatter.Deserialize(stream);
            stream.Close();
            return clonedObj;
        }
    }

    /// <summary>
    /// Class Job
    /// </summary>
    [Serializable]
    public class Job
    {
        /// <summary>
        /// Gets or sets the name of the job.
        /// </summary>
        /// <value>The name of the job.</value>
        public string JobName
        {
            get;
            set;
        }
    }

結果如下:

 

 

 3 不用加Serializable的深復制方法

        public static T DeepCopy<T>(T obj)
        {
            object retval;
            using (MemoryStream ms = new MemoryStream())
            {
                XmlSerializer xml = new XmlSerializer(typeof(T));
                xml.Serialize(ms, obj);
                ms.Seek(0, SeekOrigin.Begin);
                retval = xml.Deserialize(ms);
                ms.Close();
            }
            return (T)retval;
        }

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM