【轉】.NET深入學習筆記(4):深拷貝與淺拷貝(Deep Copy and Shallow Copy)

今天繼續利用準備WSE安全開發文章的空閑時間,完善《.NET深入學習筆記》系列(基本都是.Net重要的知識點,我都做了詳細的總結,是什么、為什么、和怎么實現)。想必很多人也接觸過這兩個概念。做過C++的人對深淺拷貝的概念一定不會陌生。而其很多C#高級軟件工程師的面試里也會問到深淺拷貝相關的問題。我今天就在總結一下,并且添加了詳細的代碼實現,與大家分享。一起學習一下C#的深拷貝與淺拷貝(Deep Copy and Shallow Copy)的機制。全文還是分四部分:1.基本概念? 2.深拷貝與淺拷貝實現機制 3.代碼實現和分析 4.總結。下面我們來進入正式的學習。

???1.基本概念:

???????首先我們應該了解一下什么叫深拷貝與淺拷貝(Deep Copy and Shallow Copy)

????? a.淺拷貝(Shallow Copy影子克隆):只復制對象的基本類型,對象類型,仍屬于原來的引用。
????? b.深拷貝(Deep Copy 深度克隆):不緊復制對象的基本類,同時也復制原對象中的對象.完全產生新對象。

????? 我們知道,在C++中有拷貝構造函數和拷貝賦值函數的概念。淺拷貝就是成員數據之間的一一賦值:把值賦給一一賦給要拷貝的值。但是可能會有這樣的情況:對象還包含資源,這里的資源可以指堆資源,或者一個文件。當值拷貝的時候,兩個對象就有用共同的資源,同時對資源可以訪問,這樣就會出問題。深拷貝就是用來解決這樣的問題的,它把資源也賦值一次,使對象擁有不同的資源,但資源的內容是一樣的。對于堆資源來說,就是在開辟一片堆內存,把原來的內容拷貝。??

??? 如果你拷貝的對象中引用了某個外部的內容(比如分配在堆上的數據),那么在拷貝這個對象的時候,讓新舊兩個對象指向同一個外部的內容,就是淺拷貝;如果在拷貝這個對象的時候為新對象制作了外部對象的獨立拷貝,就是深拷貝??
?? 這個C#里的概念與C++類似。我們可以參考以前的概念理解。?深拷貝與淺拷貝之間的區別基本可以從定義看出。首先淺拷貝是指將對象中的數值類型的字段拷貝到新的對象中,而對象中的引用型字段則指復制它的一個引用到目標對象。如果改變目標對象中引用型字段的值他將反映在原是對象中,也就是說原始對象中對應的字段也會發生變化。

??? 深拷貝拷貝不同的是對于引用拷貝的處理,深拷貝將會在新對象中創建和原是對象中對應值類型的字段并且賦值。淺拷貝不會創建新引用類型,會返回相同的類型引用。深拷貝會重新創建新對象,返回新對象的引用字。C#中的觀察者模式就是淺拷貝的例子。我們保留的只是對象的副本。

?

?

? 2.深拷貝與淺拷貝實現機制:

?

??? 從上面的概念我們了解了C#深拷貝與淺拷貝(Deep Copy and Shallow Copy)的不同之處。這個也就決定了兩者有不同的實現方式。

???? 對于值類型:
??? a.淺拷貝:?通過賦值等操作直接實現,將對象中的值類型的字段拷貝到新的對象中。??????
??? b.深拷貝:通過賦值等操作直接實現,將對象中的值類型的字段拷貝到新的對象中。???和淺拷貝相同

??? 對于引用類型:
??? a.淺拷貝:?MemberwiseClone 方法創建一個淺副本,方法是創建一個新對象,如果字段是值類型的,則對該字段執行逐位復制。如果字段是引用類型,則復制引用原始對象,與原對象引用同一對象。

??? b.深拷貝:拷貝對象應用,也拷貝對象實際內容,也就是創建了一個新的改變新對象 不會影響到原始對象的內容?
這種情況需要為其實現ICloneable接口中提供的Clone方法。

?? 差別就是在對于引用類型的實現深拷貝和淺拷貝的時候的機制不同,前者是MemberwiseClone 方法實現,后者是通過繼承實現ICloneable接口中提供的Clone方法,實現對象的深拷貝。

? 3.代碼實現和分析:

?? 下面我們來看看具體的代碼實現部分,首先介紹的還是值類型的。

??? a.值類型淺拷貝的實現。代碼如下:

///?<summary>
????????
///??數組的=賦值(直接拷貝),也就是引用傳遞,指向的是同一個地址:
????????
///?</summary>
????????public?void?MethodShallowCopyDirectly()
????????{
????????????
int[]?ArrayInt?=?{?0,?1,?2,?3?};

????????????
//所以改變其中任意一個變量的值,另一個也會被改變
????????????int[]?NewArrayInt?=?ArrayInt;
????????????
//改變新的數組變量:
????????????NewArrayInt[0]?=?8;
????????????Console.WriteLine(
"數組的復制(直接拷貝),改變新數組第一值為8,原值{0},新值{1}",?ArrayInt[0],?NewArrayInt[0]);
????????}
????????
///?<summary>
????????
///?ArrayInt.CopyTo,創建以個新數組,不影響原來的值
????????
///?</summary>
????????public?void?MethodShallowCopyArrayCopyTo()
????????{
????????????
int[]?ArrayInt?=?{?0,?1,?2,?3?};?????

????????????
//CopyTo()方法
????????????int[]?NewArrayInt?=?new?int[5];//創建以個新數組,按值拷貝,不影響原來的值
????????????ArrayInt.CopyTo(NewArrayInt,?0);
????????????NewArrayInt[
0]?=?8;
????????????Console.WriteLine(
"Array.CopyTo,改變新數組第一值為8,原值{0},新值{1}",?ArrayInt[0],?NewArrayInt[0]);
????????
????????}
????????
///?<summary>
????????
///?Array.Copy淺拷貝,值類型的淺拷貝,創建以個新數組,按值拷貝,不影響原來的值
????????
///?</summary>
????????public?void?MethodShallowCopyArrayCopy()
????????{
????????????
int[]?ArrayInt?=?{?0,?1,?2,?3?};
????????????
//Copy()方法
????????????int[]?NewArrayInt?=?new?int[4];
????????????Array.Copy(ArrayInt,?NewArrayInt,?
0);//創建以個新數組,按值拷貝,不影響原來的值
????????????NewArrayInt[0]?=?8;
????????????Console.WriteLine(
"Array.Copy,改變新數組第一值為8,原值{0},新值{1}",?ArrayInt[0],?NewArrayInt[0]);

????????}
????????
///?<summary>
????????
///?Array.Clone(),淺拷貝
????????
///?</summary>
????????public?void?MethodShallowCopyArrayClone()
????????{
????????????
int[]?ArrayInt?=?{?0,?1,?2,?3?};
????????????
//Array?Clone()方法
????????????int[]?NewArrayInt?=?ArrayInt.Clone()?as?int[];//按值拷貝,不影響原來的值
????????????NewArrayInt[0]?=?8;
????????????Console.WriteLine(
"Array.Clone(),改變新數組第一值為8,原值{0},新值{1}",?ArrayInt[0],?NewArrayInt[0]);
????????}
????????
///?<summary>
????????
///?.淺拷貝:(引用類型),數組中的元素是引用類型,復制的是它的一個引用,改變新拷貝會改變原對象
????????
///?</summary>
????????public?void?MethodShallowCopyStringArrayCopyTo()
????????{
????????????
string[]?sArray?={?"string0",?"string1",?"string2"?};
????????????
string[]?sNewArray?=?sArray;
????????????
//淺拷貝一個新對象
????????????sArray.CopyTo(sNewArray,?0);

????????????
//改變新對象的值這個時候源對象中的值也會被改變
????????????sNewArray[0]?=?"FrankXuLei";
????????????Console.WriteLine(
"數組的淺拷貝:(引用類型),改變第一值為FrankXuLei,原值{0},新值{1}",?sArray[0],?sNewArray[0]);
????????}
????????
///?<summary>
????????
///??//字符串數組的深拷貝,如果需要包含引用類型的數組的深副本,就必須迭代數組,創建新對象
????????
///?</summary>
????????public?void?MethodDeepCopyStringArray()
????????{
????????????
string[]?sArray?=?new?string[]?{?"string0",?"string1",?"string2",?"string3"?};
????????????
string[]?sNewArray?=?new?string[4];//迭代數組,創建新對象
????????????for?(int?i?=?0;?i?<?sArray.Length;?i++)
????????????{
????????????????
string?sTemp?=?string.Empty;
????????????????sTemp?
=?sArray[i];
????????????????sNewArray[i]?
=?sTemp;
????????????}
????????????sNewArray[
0]?=?"FrankXuLei";
????????????Console.WriteLine(
"數組的復制(直接拷貝),改變新數組第一值為FrankXuLei,原值{0},新值{1}",?sArray[0],?sNewArray[0]);
????????}

???????數組的=賦值(直接拷貝),也就是引用傳遞,指向的是同一個地址,

所以改變其中任意一個變量的值,另一個也會被改變。ArrayInt.CopyTo,創建以個新數組,改變新的數組變量不影響原來的值。Array.Copy淺拷貝,值類型的淺拷貝,創建以個新數組,按值拷貝,不影響原來的值?.淺拷貝:(引用類型),數組中的元素是引用類型,復制的是它的一個引用,改變新拷貝會改變原對象.

?? b.引用類型的深拷貝實現:

??? 定義了以個汽車類,繼承接口繼承接口ICloneable

?

public?class?CarDeepClone?:?ICloneable
????{
????????
//名稱,引用類型
????????public?string?_name?=?string.Empty;
????????
//價格,值得類型
????????public?int?_price?=?0;
????????
//構造函數
????????public?CarDeepClone()
????????{
????????}
????????
//重載構造函數
????????public??CarDeepClone(string?name,?int?price)
????????{
????????????_name?
=?name;
????????????_price?
=?price;
????????}
????????
//深拷貝,需要重新生成對象,返回的新對象的實例
????????public?object?Clone()
????????{

????????????
//深復制??
????????????CarDeepClone?obj?=?new?CarDeepClone();//重新創建?CarDeepClone的對象
????????????
//obj.Member=???(ClassA)Member.Clone();??
????????????return?obj;
????????}
????}

???c.引用類型的淺拷貝實現:

?? 淺拷貝實現的方法是this.MemberwiseClone();創建當前對象的淺副本 ,返回相同的對象引用。而深拷貝的實現代碼是通過?CarDeepClone obj = new CarDeepClone();重新創建 CarDeepClone的對象。這個是兩者在實現上不同的地方。

public?class?CarShallowClone?:?ICloneable
????{
????????
//名稱,引用類型
????????public?string?_name?=?string.Empty;
????????
//價格,值得類型
????????public?int?_price?=?0;
????????
//構造函數
????????public??CarShallowClone(string?name,?int?price)
????????{
????????????_name?
=?name;
????????????_price?
=?price;
????????}
????????
//淺拷貝,MemberwiseClone方式返回對象的淺副本
????????public?object?Clone()
????????{
????????????
return?this.MemberwiseClone();//創建當前對象的淺副本?,返回相同的對象引用
????????}
????}

?? d.客戶端測試代碼實現:

??? 包括值類型的淺拷貝和string類型數組的深拷貝的實現測試。以及對象的深拷貝和淺拷貝的測試。具體代碼如下:

ValueTypeCopy?_ShallowCopy?=?new?ValueTypeCopy();
????????????Console.WriteLine(
"Value?Type?Shallow?Copy?Demo?值類型淺拷貝。。。。。。。。。。。。。。。。。。");
????????????_ShallowCopy.MethodShallowCopyDirectly();
//直接賦值
????????????_ShallowCopy.MethodShallowCopyArrayClone();//調用數組的Clone()方法,淺副本
????????????_ShallowCopy.MethodShallowCopyArrayCopy();//ArrayCopy方法
????????????_ShallowCopy.MethodShallowCopyArrayCopyTo();//ArrayCopyTo()方法
????????????_ShallowCopy.MethodShallowCopyStringArrayCopyTo();//ArrayCopyTo()方法
?
????????????_ShallowCopy.MethodDeepCopyStringArray();
//深拷貝字符數組

?

????????????
//DeepCopy?Test深拷貝,重新生成對象,對新對象的修改不會改變原來對象的值
????????????Console.WriteLine("Object?Deep????Copy?Demo??對象深拷貝。。。。。。。。。。。。。。。。。。。。。");
????????????CarDeepClone?_CarDeepClone1?
=?new?CarDeepClone("Benz700",700);
????????????
//深拷貝
????????????Console.WriteLine("DeepCopy?Test深拷貝,原對象名字{0}",?_CarDeepClone1._name);
????????????CarDeepClone?_CarDeepClone2?
=?_CarDeepClone1.Clone()?as?CarDeepClone;

????????????Console.WriteLine(
"DeepCopy?Test深拷貝,新對象名字{0}",?_CarDeepClone2._name);
????????????
//修改新對象的名字
????????????_CarDeepClone2._name?=?"Benz800";
????????????Console.WriteLine(
"DeepCopy?Test深拷貝,新對象名字修改為{0}",?_CarDeepClone2._name);
????????????
//輸出對象信息
????????????Console.WriteLine("DeepCopy?Test深拷貝,原對象名字為{0},新對象名字為{1}",?_CarDeepClone1._name,?_CarDeepClone2._name);

????????????
//ShallowCopy?Test淺拷貝,新對象的修改會改變原來對象的值得
????????????Console.WriteLine("Object?Shallow?Copy?Demo??對象淺拷貝。。。。。。。。。。。。。。。。。。。。。");
????????????CarShallowClone?_CarShallowClone1?
=?new?CarShallowClone("BMW3",?300);
????????????Console.WriteLine(
"ShallowCopy?Test淺拷貝,原對象名字{0}",?_CarShallowClone1._name);
????????????
//淺拷貝對象
????????????CarShallowClone?_CarShallowClone2?=?_CarShallowClone1.Clone()?as?CarShallowClone;
????????????Console.WriteLine(
"ShallowCopy?Test淺拷貝,新對象名字{0}",?_CarShallowClone2._name);
????????????
//修改新對象名字
????????????_CarShallowClone2._name?=?"BMW7";
????????????Console.WriteLine(
"ShallowCopy?Test淺拷貝,新對象名字修改為{0}",?_CarShallowClone2._name);
????????????
//輸出對象信息
????????????Console.WriteLine("ShallowCopy?Test淺拷貝,原對象名字{0},新對象名字{1}",?_CarShallowClone1._name,?_CarShallowClone2._name);
???????????

?????

?

??? 首先測試的值類型的不同的淺拷貝方法,實例化類ValueTypeCopy _ShallowCopy = new ValueTypeCopy();
????進行 值類型淺拷測試貝。分別包括:?? _ShallowCopy.MethodShallowCopyDirectly();直接賦值拷貝,
??????????? _ShallowCopy.MethodShallowCopyArrayClone();調用數組的Clone()方法,淺副本
??????????? _ShallowCopy.MethodShallowCopyArrayCopy();ArrayCopy方法
??????????? _ShallowCopy.MethodShallowCopyArrayCopyTo();ArrayCopyTo()方法
??????????? _ShallowCopy.MethodShallowCopyStringArrayCopyTo();ArrayCopyTo()方法
???????????? _ShallowCopy.MethodDeepCopyStringArray();深拷貝字符數組
后面代碼主要是對對象深淺拷貝的不同測試。

運行結果如下圖:

CloneTest.gif?

4.總結

???? 通過以上內容的學習,希望大家對C#中的深拷貝與淺拷貝(Deep Copy and Shallow Copy)的機制能有更深入的了解。我在總結這個文章的時候也查閱了MSDN及C#書籍等資料。與大家一起分享。有問題的也可以留言一起交流~共同學習進步~(最后附上本次實現的代碼。下載地址

/Files/frank_xl/CloneDemoFrankXuLei.zip?。前幾天忙碩士論文的事情,沒時間更新blog,現在抓緊時間繼續準備WSE3.0安全開發的文章,應該最近會寫出來。主要是涉及到的知識點很多,需要時間學習,而且開發環境配置比較復雜。代碼插入出了問題,有js錯誤,請大家下載代碼)

轉載于:https://www.cnblogs.com/jiangj/archive/2010/08/20/1804518.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379040.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379040.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379040.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c語言數組-1_C數組-智能問題與解答

c語言數組-1C programming Arrays (One-D Array, Two-D Array) Aptitude Questions and Answers : In this section you will find C Aptitude Questions and Answers on One Dimensional (1D) and Two Dimensional (2D) array. C編程數組(一維數組&#xff0c;二維數組)能力問…

abap 添加alv上的工具欄的按鈕_Excel里的置頂功能——快速訪問工具欄

100萬職場人都在看后臺回復禮包領199元職場干貨大家好&#xff0c;我是小可~今天跟大家分享一個提高Excel操作效率的小技巧自定義你的快速訪問工具欄設置后的效果▼▼▼也就是把你最經常用到的兩三個功能放到快速訪問工具欄可以一眼就找到這些功能不需要靠快捷鍵或者功能選項卡…

用遞歸法求12+22+...+n2的值

思路分析: 談到遞歸,我個人會聯想到數學里面的通式。因為遞歸調用的函數的對應法則是相同的。例如這道題:f(x)=x。這個就是函數通式,只不過把每個求得的結果進行累加求和即可。用戶輸入5的時候,會出現f(5)=5,之后再進行x減一操作,執行f(4)=4,最后將每個進行累加即可。…

機器學習資料推薦

機器學習資料推薦 機器學習的資料 1:斯坦福大學視頻(作為入門教程&#xff0c;網易有中文字幕&#xff0c;而且講義也有翻譯版本&#xff09;20集200左右講義 2&#xff1a;機器學習 Tom M.Mitchell(雖然出版10多年&#xff0c;但是通俗易懂的內容&#xff0c;讓讀者對機器學習…

ffplay源碼(版本:ffmpeg-4.2.1)

ffplay源碼&#xff08;版本&#xff1a;ffmpeg-4.2.1&#xff09; /** Copyright (c) 2003 Fabrice Bellard** This file is part of FFmpeg.** FFmpeg is free software; you can redistribute it and/or* modify it under the terms of the GNU Lesser General Public* Lic…

stringwriter_Java StringWriter toString()方法與示例

stringwriterStringWriter類的toString()方法 (StringWriter Class toString() method) toString() method is available in java.io package. toString()方法在java.io包中可用。 toString() method is used to represent the buffer current value in terms of string. toStr…

編寫一個函數,計算下式當n=10和n=100的值。

思路分析: 首先,我個人看法:當我拿到這道題的時候,我會把它當成一道數學題對待。分子是動的,恒為一,分母是進行依次增加的。且奇數項為正,偶數項為負。因為設計運算出現的是分數,故,設計選取存儲類型為double。 找出問題: ①正負號問題、②分母問題、③累計求和問題…

POJ 1001 大數的乘法

對這道題的理解 大數的乘法 關鍵是 實型的 那么首先就是數出來小數點有幾位這個相信很簡單 從后面往前數剛開始0 不算接著就是遇到小數點結束如果沒有小數點 那么置為0 接著就是輸出地時候首先算出小數點的位置然后輸出 你想怎么樣都行 從后往前數這個時候輸出 那么就是你也…

鈴木uy125摩托車機油_濟南鈴木安徽發布國四新車—6480元瑞夢125、9380元UY125

安徽合肥&#xff0c;這個具有兩千多年歷史的古城&#xff0c;以“三國故地、包拯家鄉”而聞名海內外&#xff0c;2019年4月22日濟南鈴木為這座城市帶來一份驚喜&#xff0c;今年正值國四執行&#xff0c;濟南鈴木旗下兩款國四新車瑞夢125與UY125正式在合肥與大家相見。濟南鈴木…

Andrej Karpathy最新大模型入門視頻講解

最近這兩天&#xff0c;特斯拉前AI總監 現在在OpenAI的安德烈卡帕西&#xff08;Andrej Karpathy&#xff09;的新教程火了 這次 他專門面向普通大眾做了一個關于大語言模型的科普視頻 時長1個小時&#xff0c;全部為“非技術介紹”&#xff0c; 涵蓋了模型推理、訓練、微…

Jquery 尋找父、子、兄弟節點

JQUERY的父&#xff0c;子&#xff0c;兄弟節點查找方法 jQuery.parent(expr) 找父親節點&#xff0c;可以傳入expr進行過濾&#xff0c;比如$("span").parent()或者$("span").parent(".class") jQuery.parents(expr),類似于jQuery.parents(exp…

編寫一個程序,計算用戶輸入的起始時間到終止時間之間相隔的天數。

思路分析&#xff1a; 閏年&#xff1a;閏年又分為普通閏年和世紀閏年 普通閏年&#xff1a;能被4整除且不能被100整除的為閏年(2004為閏年&#xff0c;1999不是閏年) 世紀閏年&#xff1a;能被400整除的是閏年(2020年是閏年&#xff0c;1900年不是閏年) 閏年共有366天&#x…

longvalue_Java Short類longValue()方法及示例

longvalue短類longValue()方法 (Short class longValue() method) longValue() method is available in java.lang package. longValue()方法在java.lang包中可用。 longValue() method is used to return the value denoted by this Short object converted to type long (by …

mvc的Controller返回值類型ActionResult詳解

一、簡介 ActionResult 操作方法通過執行工作并返回操作結果來響應用戶輸入。 操作結果表示框架將代表操作方法執行的命令。 ActionResult 類是操作結果的基類。 以下類型從 ActionResult 派生&#xff1a; ContentResult EmptyResult FileResult HttpUnauthorizedResult …

柵格布局一般怎么用_建筑混凝土色差大怎么辦?用這種方法處理,一般都看不出來...

由于模板銹蝕、脫模劑污染、原材料等原因&#xff0c;建筑混凝土成形后經常會遇到顏色不一致的現象&#xff0c;為此我們總結了混凝土面色差調整施工工藝&#xff0c;可供大家參考使用。一、混凝土面色差調整施工工藝流程及說明基層表面打磨→吸塵器吸塵→濕潤墻面→素水泥處理…

Java SimpleTimeZone equals()方法與示例

SimpleTimeZone類的equals()方法 (SimpleTimeZone Class equals() method) equals() method is available in java.util package. equals()方法在java.util包中可用。 equals() method is used to check whether this SimpleTimeZone and the given object (ob) are equals or …

FusionChart完全入門手冊4

想不想打造讓人震撼的圖表系統&#xff0c;想不想做出和別人不一樣的圖表&#xff0c;從本節起&#xff0c;我就帶領大家走入這片神奇的土地&#xff0c;讓大家去采摘屬于自己的創意之果&#xff0c;我們的目標是------個性無罪&#xff0c;個性萬歲&#xff01; 問題三、如何做…

ffplay分析(音頻解碼線程的操作)

《ffplay的數據結構分析》 《ffplay分析&#xff08;從啟動到讀取線程的操作&#xff09;》 《ffplay分析&#xff08;視頻解碼線程的操作&#xff09;》 《ffplay 分析&#xff08;音頻從Frame(解碼后)隊列取數據到SDL輸出&#xff09;》 《ffplay分析 &#xff08;視頻從Fram…

More Effective C++ (運算符)

4.1&#xff1a;謹慎定義類型轉換函數<1>容易的方法是利用一個最新的編譯器特性&#xff1a;explicit關鍵字<2>C編譯器把">>"作為一個符號來解釋&#xff0c;在兩個">"間沒有空格&#xff0c;語句會產生語法錯誤。<3>隱式類型轉…

大綱(二)

一、數據結構就是邏輯結構存儲結構(物理結構)相應操作(算法實現) 二、邏輯結構 集合1:1 線性結構1:n 樹m:n 圖 主要是可以畫到紙上進行分析的結構圖就是邏輯結構&#xff0c;分析問題可以得出唯一一個邏輯結構 三、存儲結構(物理結構) 順序存儲結構(例如:線性表)鏈式存儲結…