C#中深拷貝和淺拷貝的介紹與用法_第1頁
C#中深拷貝和淺拷貝的介紹與用法_第2頁
C#中深拷貝和淺拷貝的介紹與用法_第3頁
C#中深拷貝和淺拷貝的介紹與用法_第4頁
C#中深拷貝和淺拷貝的介紹與用法_第5頁
已閱讀5頁,還剩3頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

第C#中深拷貝和淺拷貝的介紹與用法一、什么是深拷貝和淺拷貝

對于所有面向?qū)ο蟮恼Z言,復制永遠是一個容易引發(fā)討論的題目,C#中也不例外。此類問題在面試中極其容易被問到,我們應該在了解淺拷貝和深拷貝基本概念的基礎上,從設計的角度進一步考慮如何支持對象的拷貝。

在System.Object類中,有一個受保護的方法object.MemberwiseClone(),這個方法實現(xiàn)了對象的復制。事實上,它所實現(xiàn)的就是我們所稱的淺拷貝。

深拷貝:指的是拷貝一個對象時,不僅僅把對象的引用進行復制,還把該對象引用的值也一起拷貝。這樣進行深拷貝后的拷貝對象就和源對象互相獨立,其中任何一個對象的改動都不會對另外一個對象造成影響。比如一個黃狗叫大黃,使用克隆術克隆另外一個黃狗叫小黃,這樣大黃和小黃就相對獨立了,他們不互相影響。在.NET中int,double以及結(jié)構(gòu)體和枚舉等。

inta=12;

intc=a;//進行了深拷貝

c=232//不影響

淺拷貝:指的是拷貝一個對象時,僅僅拷貝對象的引用進行拷貝,但是拷貝對象和源對象還是引用同一份實體。此時,其中一個對象的改變都會影響到另一個對象。就像一個人改名了一樣,他還是這個人,只不過名字變了而已。

publicclassYDog

publicstringName{get;set;}

classProgram

staticvoidMain(string[]args)

YDogsourceP=newYDog(){Name="大黃"};

YDogcopyP=sourceP;//淺拷貝

copyP.Name="小黃";//拷貝對象改變Name值

//結(jié)果都是"小黃",因為實現(xiàn)的是淺拷貝,一個對象的改變都會影響到另一個對象

Console.WriteLine("YDog.Name:[SourceP:{0}][CopyP:{1}]",sourceP.Name,copyP.Name);

Console.Read();

}

所謂的淺拷貝,是指拷貝一個對象的時候,拷貝原始對象中所有的非靜態(tài)值類型成員和所有的引用類型成員的引用。換言之,新的對象和原始對象將共享所有引用類型成員的實際對象。而相對的,深拷貝是指不僅復制所有的非靜態(tài)值類型成員,而且也復制所有引用類型成員的實際對象。深拷貝和淺拷貝的概念是遞歸的,也就是說當引用類型成員中包含另外一個引用類型成員時,拷貝的時候?qū)ζ鋬?nèi)部成員實行同樣的復制策略。

淺拷貝示意圖如下所示:

深拷貝示意圖如下圖所示:

類型基類System.Object已經(jīng)為所有類型都實現(xiàn)了淺拷貝,類型所要做的就是公開一個復制的接口,而通常的,這個接口會借由實現(xiàn)ICloneable接口來實現(xiàn)。ICLoneable只包含一個Clone方法。該方法既可以被實現(xiàn)為淺拷貝也可以被實現(xiàn)為深拷貝,具體如何取舍需要根據(jù)具體類型的需求來決定。下面的代碼提供了一個深拷貝的簡單示例:

usingSystem;

namespaceDeepCopy

classProgram

staticvoidMain(string[]args)

//定義原始對象

DpCopydc=newDpCopy();

dc._i=10;

dc._a=newA();

//定義深拷貝對象

DpCopydeepClone=(DpCopy)dc.Clone();

//定義淺拷貝對象

DpCopyshadowclone=(DpCopy)dc.MemberwiseClone();

//深拷貝的復制對象將擁有自己的引用類型成員對象

//所以這里的賦值不會影響原始對象

deepClone._a._s="我是深拷貝的A";

Console.WriteLine(dc);

Console.WriteLine(deepClone);

Console.WriteLine("\r\n");

//淺拷貝的復制對象共享原始對象的引用類型成員對象

//所以這里的賦值將影響原始對象

shadowclone._a._s="我是淺拷貝的A";

Console.WriteLine(dc);

Console.WriteLine(shadowclone);

Console.ReadKey();

publicclassDpCopy:ICloneable

publicint_i=0;

publicA_a=newA();

publicobjectClone()

//實現(xiàn)深拷貝

DpCopynewDc=newDpCopy();

//重新實例化一個引用類型變量

newDc._a=newA();

//給新引用類型變量的成員值

newDc._a._s=_a._s;

newDc._i=_i;

returnnewDc;

//實現(xiàn)淺拷貝

publicnewobjectMemberwiseClone()

returnbase.MemberwiseClone();

///summary

///重寫類的ToString()方法

////summary

///returns/returns

publicoverridestringToString()

return"I的值為:"+_i.ToString()+",A為:"+_a._s;

///summary

///包含一個引用成員的類型

////summary

publicclassA

publicstring_s="我是原始A";

}

在上面的代碼中,類型DpCopy通過ICLoneable接口的Clone方法提供了深拷貝,并且通過提供一個MemberwiseClone的公共方法提供了淺拷貝。DpCopy類型具有一個值類型成員和一個引用類型成員,引用類型成員在淺拷貝和深拷貝時將展現(xiàn)不同的特性,淺拷貝的原始對象和目標對象公用了一個引用類型成員對象,這在程序的執(zhí)行結(jié)果中可以清楚地看到:

有的參考資料上說C#中的深拷貝通過ICloneable接口來實現(xiàn)。這句話并不正確。事實上任何名字的方法都可以用來實現(xiàn)深拷貝,并且沒有任何語法來規(guī)定深拷貝只能通過Clone方法來實現(xiàn)。Clone這個名字只是一種習慣的稱呼,而實現(xiàn)ICloneable只能帶來一般接口的通用便利性,而并沒有任何關于拷貝的特殊性。

一般可被繼承的類型應該避免實現(xiàn)ICloneable接口,因為這樣做將強制所有的子類型都需要實現(xiàn)ICloneable接口,否則將使類型的深拷貝不能覆蓋子類的新成員。

實現(xiàn)深拷貝

1、新建一個對象,一個一個的重新賦值,麻煩一點

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

usingSystem.Threading.Tasks;

namespaceServiceTest

publicclassProgram

staticvoidMain(string[]args)

YDogDog=newYDog(){Name="大黃"};

YDogNewDog=newYDog();

NewDog.Name=Dog.Name;

Console.WriteLine($"Dog.Name:{Dog.Name},NewDog.Name:{NewDog.Name}");

Console.Read();

}

輸出結(jié)果

2、利用反射實現(xiàn)深拷貝

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Reflection;

usingSystem.Text;

usingSystem.Threading.Tasks;

namespaceServiceTest

publicclassProgram

staticvoidMain(string[]args)

YDogDog=newYDog(){Name="大黃"};

YDogNewDog=(YDog)DeepCopy(Dog);

NewDog.Name=Dog.Name;

Console.WriteLine($"Dog.Name:{Dog.Name},NewDog.Name:{NewDog.Name}");

Console.Read();

/*利用反射實現(xiàn)深拷貝*/

publicstaticobjectDeepCopy(object_object)

TypeT=_object.GetType();

objecto=Activator.CreateInstance(T);

PropertyInfo[]PI=T.GetProperties();

for(inti=0;iPI.Length;i++)

PropertyInfoP=PI[i];

P.SetValue(o,P.GetValue(_object));

returno;

}

輸出結(jié)果

3、利用序列化和反序列化來實現(xiàn),如下代碼

usingNewtonsoft.Json;

usingSystem;

usingSystem.Collections.Generic;

usingSystem.IO;

usingSystem.Linq;

usingSystem.Reflection;

usingSystem.Runtime.Serialization.Formatters.Binary;

usingSystem.Text;

usingSystem.Threading.Tasks;

usingSystem.Xml.Serialization;

namespaceServiceTest

publicclassProgram

staticvoidMain(string[]args)

YDogDog=newYDog(){Name="大黃"};

//YDogNewDog=(YDog)DeepCopy(Dog);

//NewDog.Name=Dog.Name;

//序列化實現(xiàn)

YDogNewDog=(YDog)DeepCopyYDog(Dog);

Console.WriteLine($"Dog.Name:{Dog.Name},NewDog.Name:{NewDog.Name}");

Console.Read();

/*利用反射實現(xiàn)深拷貝*/

publicstaticobjectDeepCopy(object_object)

TypeT=_object.GetType();

objecto=Activator.CreateInstance(T);

PropertyInfo[]PI=T.GetProperties();

for(inti=0;iPI.Length;i++)

PropertyInfoP=PI[i];

P.SetValue(o,P.GetValue(_object));

returno;

//利用XML序列化和反序列化實現(xiàn)

public

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論