正確實現淺拷貝和深拷貝

2022-03-12 17:43:00 字數 2044 閱讀 8875

為物件建立副本的技術稱為拷貝(也叫轉殖)。我們將拷貝分為淺拷貝和深拷貝。

淺拷貝:將物件中的所有字段複製到新的物件(副本)中。其中,值型別欄位的值被複製到副本中後,在副本中的修改不會影響到源物件對應的值。而引用型別的字段被複製到副本中的是引用型別的引用,而不是引用的物件,在副本中對引用型別的字段值做修改會影響到源物件本身。

深拷貝:同樣,將物件中的所有字段複製到新的物件中。不過,無論是物件的值型別字段,還是引用型別字段,都會被重新建立並賦值,對於副本的修改,不會影響到源物件本身。

無論是淺拷貝還是深拷貝,微軟都建議用型別繼承icloneable介面的方式明確告訴呼叫者:該型別可以被拷貝。當然,icloneable介面只提供了乙個宣告為clone的方法,我們可以根據需求在clone方法內實現淺拷貝或深拷貝。乙個簡單的淺拷貝的實現**如下所示:

class

employee : icloneable

public

int age

public department department

public

object

clone()

}class

department

public

override

string

tostring()

}//呼叫employee mike = new

employee

};employee rose = mike.clone() as

employee;

console.writeline(mike.idcode);

console.writeline(mike.age);

console.writeline(mike.department);

console.writeline(

"改變mike的值");

mike.idcode = "

nb456";

mike.age = 24

;mike.department.name = "

dep2";

console.writeline(rose.idcode);

console.writeline(rose.age);

console.writeline(rose.department);

輸出為:

nb123

18dep1

改變mike的值

nb123

18dep2

注意到employee的idcode屬性是string型別。理論上string型別是引用型別,但是由於該引用型別的特殊性(無論是實現還是語義),object.memberwiseclone方法仍舊為其建立了副本。也就是說,在淺拷貝過程,我們應該將字串看成是值型別。

employee的department屬性是乙個引用型別,所以,如果改變了源物件mike中的值,副本rose中的值也會隨之一起變動。

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

由於介面icloneable只有乙個模稜兩可的clone方法,所以如果要在乙個類中同時實現深拷貝和淺拷貝,只能由我們自己實現兩個額外的方法,宣告為deepclone和shallow。employee的最終版本看起來應該像如下的形式:

[serializable]

class

employee : icloneable

public

int age

public department department

public

object

clone()

public

employee deepclone()

}public

employee shallowclone()

}

需要注意在department類中加上可序列化標籤;

以上內容引用自《編寫高質量** 改善c#程式的157個建議》

正確實現淺拷貝和深拷貝

淺拷貝和深拷貝的區別 淺拷貝 修改副本的值型別字段不會影響源物件對應的字段,修改副本的引用型別欄位會影響源物件,因為源物件複製給副本物件的時候,是引用型別的引用位址,也就是兩者引用的是同乙個物件。深拷貝 無論值型別還是引用型別的字段,修改副本物件不會影響源物件,即使是引用型別,也是重新建立了乙個新的...

深拷貝和淺拷貝

淺拷貝就是物件的資料成員之間的簡單賦值,如你設計了乙個沒有類而沒有提供它的複製建構函式,當用該類的乙個物件去給令乙個物件賦值時所執行的過程就是淺拷貝,如 class a a private int data int main 這一句b a 就是淺拷貝,執行完這句後b.data 5 如果物件中沒有其他...

淺拷貝和深拷貝

以下情況都會呼叫拷貝建構函式 乙個物件以值傳遞的方式傳入函式體 例如 已知class a,class b void func a a void func a a func b b 此時函式對b的操作是呼叫拷貝建構函式後的臨時拷貝物件。多數傳指標 乙個物件以值傳遞的方式從函式返回 如 return b...