1. 程式人生 > >C#淺拷貝和深拷貝

C#淺拷貝和深拷貝

C#中的物件拷貝問題;
所謂的物件拷貝,其實就是為物件建立副本,C#中將拷貝分為兩種,分別為淺拷貝和深拷貝;
所謂淺拷貝就是將物件中的所有欄位複製到新的副本物件中;淺拷貝對於值型別與引用型別的方式有區別,值型別欄位的值被複制到副本中後,在副本中的修改不會影響源物件對應的值;然而對於引用型別的欄位被複制到副本中的卻是引用型別的引用,而不是引用的物件,在副本中對引用型別的欄位值被修改後,源物件的值也將被修改。
深拷貝也同樣是將物件中的所有欄位複製到副本物件中,但是,無論物件的值型別欄位或者引用型別欄位,都會被重新建立並複製,對於副本的修改,不會影響到源物件的本身;

當然,無論是哪種拷貝,微軟都建議使用型別繼承ICloneable介面的方式明確告訴呼叫者,該物件是否可用被拷貝。當然了,ICloneable介面只提供了一個宣告為Clone的方法,我們可以根據需求在Clone的方法內實現淺拷貝或者是深拷貝,下面我們進行一段淺拷貝的案例,程式碼如下

class Student : ICloneable
    {
        public string IDCode { get; set; }
        public int Age { get; set; }
        public Grent Grent { get; set; }
        #region 拷貝主體
        public object Clone()
        {
            return this.MemberwiseClone();
            //throw new NotImplementedException();
        }
        #endregion
   }
    class Grent
    {
        public string Name { get; set; }
        public override string ToString()
        {
            return this.Name;
        }

    }

呼叫

Student stu1 = new Student()
            {
                IDCode = "lily",
                Age = 24,
                Grent = new Grent() { Name="五年三班"}
            };
            Student stu2 = stu1.Clone() as Student;
            if (stu2 == null) {
                Console.WriteLine("轉換失敗");
                Console.ReadKey();
                return;
            }
            Console.WriteLine(stu2.IDCode);
            Console.WriteLine(stu2.Age);
            Console.WriteLine(stu2.Grent.ToString());
            Console.WriteLine("重新為stu1賦值");
            stu1.IDCode = "Anagle";
            stu1.Age += 10;
            stu1.Grent.Name = "六年二班";
            Console.WriteLine(stu2.IDCode);
            Console.WriteLine(stu2.Age);
            Console.WriteLine(stu2.Grent.ToString());

            Console.ReadKey();

輸出結果為:
lily
24
五年三班
重新為stu1賦值
lily
24

六年二班

這裡我們需要注意一點Student中的IDCode屬性是string型別,理論上string型別是引用型別,但是由於該引用型別的特殊性,Object.MemberwiseClone方法仍舊為他建立了副本,也就是說,在淺拷貝過程中,我們應該將字串看成值型別;
因為Student中的Grent是引用型別,所以在stu1中的Grent的Name被改變的同時,副本stu2中的Grent的Name也同樣被改變。

Student的深拷貝有多鍾實現方法,最簡單的方法是手動對欄位諑個賦值,但是這種方法容易出錯,也就是說,如果型別的欄位發生變化或有增減時,那麼該拷貝方法也就要發生相應的變化,所以,建議使用序列化的形式來進行深拷貝。實現程式碼如下

[Serializable]
    class Student : ICloneable
    {
        public string IDCode { get; set; }
        public int Age { get; set; }
        public Grent Grent { get; set; }
        #region 拷貝主體
        /// <summary>
        /// 深度拷貝
        /// </summary>
        /// <returns></returns>
        public Student DeepClone() {
            using (Stream objectStream = new MemoryStream()) {
                IFormatter formatter = new BinaryFormatter();
                formatter.Serialize(objectStream, this);
                objectStream.Seek(0,SeekOrigin.Begin);
                return formatter.Deserialize(objectStream) as Student;
            }
        }
        public object Clone()
        {
            return this.MemberwiseClone();
        }
        #endregion

    }

呼叫DeepClone方法

Student stu1 = new Student()
            {
                IDCode = "lily",
                Age = 24,
                Grent = new Grent() { Name="五年三班"}
            };
            Student stu2 = stu1.DeepClone() as Student;
            if (stu2 == null) {
                Console.WriteLine("轉換失敗");
                Console.ReadKey();
                return;
            }
            Console.WriteLine(stu2.IDCode);
            Console.WriteLine(stu2.Age);
            Console.WriteLine(stu2.Grent.ToString());
            Console.WriteLine("重新為stu1賦值");
            stu1.IDCode = "Anagle";
            stu1.Age += 10;
            stu1.Grent.Name = "六年二班";
            Console.WriteLine(stu2.IDCode);
            Console.WriteLine(stu2.Age);
            Console.WriteLine(stu2.Grent.ToString());

            Console.ReadKey();

輸出結果為:
lily
24
五年三班
重新為stu1賦值
lily
24

五年三班

這次我們看到的結果已經很明顯了,深拷貝後,源物件的重新賦值與修改將不再導致副本物件被修改,這樣將很好的控制住引用型別的拷貝問題。


相關推薦

C語言中的拷貝拷貝

淺拷貝 首先看下面這段程式碼: # include<assert.h> # include<string.h> #include <stdlib.h> typedef struct Node//定義了一個結構體 { int size; char *da

C++拷貝拷貝

C++系統提供的拷貝建構函式是淺拷貝,只是簡單的值拷貝 #include<iostream> using namespace std; class Test { public: int m_a; char *name; public: Test(const c

C#拷貝拷貝

C#中的物件拷貝問題;所謂的物件拷貝,其實就是為物件建立副本,C#中將拷貝分為兩種,分別為淺拷貝和深拷貝;所謂淺拷貝就是將物件中的所有欄位複製到新的副本物件中;淺拷貝對於值型別與引用型別的方式有區別,值型別欄位的值被複制到副本中後,在副本中的修改不會影響源物件對應的值;然而對

瞭解C# Tips拷貝拷貝(轉)

引言   C#中有兩種型別變數,一種 是值型別變數,一種是引用型別變數,對於值型別變數,深拷貝和前拷貝都是通過賦值操作符號(=)實現,其效果一致,將物件中的值型別的欄位拷貝到新的物件中.這個很容易理解。 本文重點討論引

C++的拷貝拷貝

我列舉一個例子來說吧:你正在編寫C++程式中有時後用到,操作符的過載。最能體現深層拷貝與淺層拷貝的,就是‘=’的過載。看下面一個簡單的程式:class string{char *m_str;public:string(char *s){m_str=s;}string(){

python中的拷貝拷貝

div blog deep imp class pri cnblogs 字符串 style 1.淺拷貝 copy.copy() 淺拷貝是拷貝只拷貝最外一層(這裏所說的拷貝是重新生成一個內存地址,也就是只有最外層的地址是重新生成) import copy li=[23,45

引用賦值,拷貝拷貝

lan art csdn 理解 article 淺拷貝和深拷貝 blank .net hang 三種引用: http://blog.csdn.net/XIAXIA__/article/details/41652057 深拷貝和淺拷貝的理解: http://blog.csdn

【轉】python的拷貝拷貝

end ont code append pen ron 實例 賦值 深拷貝 直接賦值:其實就是對象的引用(別名)。 淺拷貝(copy):拷貝父對象,不會拷貝對象的內部的子對象。 深拷貝(deepcopy): copy 模塊的 deepcopy 方法,完全拷貝了父對象及其

js 對象的拷貝拷貝

tex bject script cnblogs ons assign 對象 而已 obj //淺拷貝,拷貝內存塊,拷貝部門代碼不共存 var obj = { a : "a", b : "b", c : { text : "這是一個文本" } }

java拷貝拷貝

一起 head 有著 cloneabl 獨立 head對象 影響 如果 覆蓋 轉:http://blog.csdn.net/u014727260/article/details/55003402 實現clone的2點: 1,clone方法是Object類的一個方法

JavaScript中的拷貝拷貝

ons == 進行 新建 手動 一個 var javascrip 空間 淺拷貝:拷貝引用。 拷貝後的新對象和源對象都是指向同一個引用地址,因此彼此之間操作互相影響。 let a = {num:1}; let b = a; console.log(a===b); //true

Python 中的拷貝拷貝

ont () ebe ans 深拷貝 函數 port epc com 1. 列表和字典,直接賦值,都是淺拷貝,即賦值雙方指向同一地址,因為 Python 對可變對象按引用傳遞。 >>> a = [1, 2, 3] >>> b

拷貝拷貝

color using href delete del private 釋放資源 class strcpy 淺拷貝和深拷貝   在某些狀況下,類內成員變量需要動態開辟堆內存,如果實行位拷貝,也就是把對象裏的值完全復制給另一個對象,如A=B。這時,如果B中有一個成員變量指針

【iOS】拷貝拷貝

簡單 HR 除了 深淺拷貝 感謝 with 分配 指針 object 淺拷貝和深拷貝 淺拷貝即指針拷貝,可以認為是給一只狗加了一條繩子;深拷貝不但拷貝了對象的指針,還在系統中在分配了一塊內存用來存放拷貝對象的內容,可以認為是產生了一條帶繩子的新狗。即淺拷貝是兩根繩子一條狗

拷貝拷貝以及copy.copy

深淺拷貝 port log HA 都是 epc cnblogs www 就是 淺拷貝:“=” >>> a=[1,2,3]>>> b=a>>> a[1, 2, 3]>>> b[1, 2, 3]>&g

js實現拷貝拷貝

擴展運算 復制對象 數據類型 對象 return strong key stringify 循環 淺拷貝和深拷貝都只針對於像Object, Array這樣的復雜對象, 區別:淺拷貝只復制對象的第一層屬性、深拷貝可以對對象的屬性進行遞歸復制 如果數組元素是基本類型,就會拷貝一

談java拷貝拷貝

原來 變量 基本數據 的區別 引用數據類型 復制 值傳遞 ec2 深拷貝和淺拷貝 前言:深拷貝和淺拷貝的區別是什麽? 淺拷貝:被復制的對象的所有變量都含有原來對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之, 淺拷貝僅僅復制所考慮的對象,而不復制它所引用的對

java拷貝拷貝(基礎也是很重要的)

inf n) vat 實現 技術 變量 hub -h 接口 對象的copy你興許只是懵懂,或者是並沒在意,來了解下吧。 對於的github基礎代碼https://github.com/chywx/JavaSE 最近學習c++,跟java很是相像,在慕課網學習c++也算是

初始JAVA中拷貝拷貝

exc 深度復制 tst 圖片 們的 over 地方 per 發生 1. 簡單變量的復制 public static void main(String[] args) { int a = 5; int b = a;

python 拷貝拷貝淺析

編碼過程中發現,列表a和b,初始化a,b拷貝a,b中元素值改過之後,a中元素也會跟著修改,一直以為是自己程式碼邏輯出了錯誤,最後發現這裡的坑是python中淺拷貝和深拷貝的機制 在python中,物件的屬性值有:物件id(記憶體地址),物件型別,物件值 id:唯一標識一個物件:if a