日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第五节 引用类型复制问题及用克隆接口ICloneable修复

發(fā)布時(shí)間:2023/12/10 C# 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第五节 引用类型复制问题及用克隆接口ICloneable修复 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

?

雖然在.Net Framework 中我們不必考慮內(nèi)在管理和垃圾回收(GC),但是為了優(yōu)化應(yīng)用程序性能我們始終需要了解內(nèi)存管理和垃圾回收(GC)。另外,了解內(nèi)存管理可以幫助我們理解在每一個(gè)程序中定義的每一個(gè)變量是怎樣工作的。

?

簡(jiǎn)介

這一節(jié)我們將介紹引用類型變量在堆中存儲(chǔ)時(shí)會(huì)產(chǎn)生的問(wèn)題,同時(shí)介紹怎么樣使用克隆接口ICloneable去修復(fù)這種問(wèn)題。

?

?

復(fù)制不僅僅是復(fù)制

?

為了更清晰的闡述這個(gè)問(wèn)題,讓我們測(cè)試一下在堆中存儲(chǔ)值類型變量和引用類型變量時(shí)會(huì)產(chǎn)生的不同情況。

?

值類型測(cè)試

?

首先,我們看一下值類型。下面是一個(gè)類和一個(gè)結(jié)構(gòu)類型(值類型),Dude類包含一個(gè)Name元素和兩個(gè)Shoe元素。我們有一個(gè)CopyDude()方法用來(lái)復(fù)制生成新Dude。

?
  • public struct Shoe{

  • public string Color;

  • }

  • ?
  • public class Dude

  • {

  • public string Name;

  • public Shoe RightShoe;

  • public Shoe LeftShoe;

  • ?
  • public Dude CopyDude()

  • {

  • Dude newPerson = new Dude();

  • newPerson.Name = Name;

  • newPerson.LeftShoe = LeftShoe;

  • newPerson.RightShoe = RightShoe;

  • ?
  • return newPerson;

  • }

  • ?
  • public override string ToString()

  • {

  • return (Name + " : Dude!, I have a " + RightShoe.Color +

  • " shoe on my right foot, and a " +

  • LeftShoe.Color + " on my left foot.");

  • }

  • ?
  • }


  • Dude類是一個(gè)復(fù)雜類型,因?yàn)橹?類型結(jié)構(gòu)Shoe是它的成員, 它們都將存儲(chǔ)在堆中。

    ?

    ?

    當(dāng)我們執(zhí)行下面的方法時(shí):

    ?
  • public static void Main()

  • {

  • Class1 pgm = new Class1();

  • ?
  • Dude Bill = new Dude();

  • Bill.Name = "Bill";

  • Bill.LeftShoe = new Shoe();

  • Bill.RightShoe = new Shoe();

  • Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";

  • ?
  • Dude Ted = Bill.CopyDude();

  • Ted.Name = "Ted";

  • Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";

  • ?
  • Console.WriteLine(Bill.ToString());

  • Console.WriteLine(Ted.ToString());

  • ?
  • }


  • 我們得到了期望的結(jié)果:

    Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot. Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot.

    如果我們把Shoe換成引用類型呢?

    ?

    引用類型測(cè)試

    ?

    當(dāng)我們把Shoe改成引用類型時(shí),問(wèn)題就產(chǎn)生了。

    ?
  • public class Shoe{

  • public string Color;

  • }


  • 執(zhí)行同樣上面的Main()方法,結(jié)果改變了,如下:

    Bill : Dude!, I have a Red shoe on my right foot, and a Red on my left foot Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot


    這并不是我們期望的結(jié)果。很明顯,出錯(cuò)了!看下面的圖解:

    ?

    因?yàn)楝F(xiàn)在Shoe是引用類型而不是值類型,當(dāng)我們進(jìn)行復(fù)制時(shí)僅是復(fù)制了指針,我們并沒(méi)有復(fù)制指針真正對(duì)應(yīng)的對(duì)象。這就需要我們做一些額外的工作使引用類型Shoe像值類型一樣工作。

    很幸運(yùn),我們有一個(gè)接口可以幫我們實(shí)現(xiàn):ICloneable。當(dāng)Dude類實(shí)現(xiàn)它時(shí),我們會(huì)聲明一個(gè)Clone()方法用來(lái)產(chǎn)生新的Dude復(fù)制類。(譯外話:復(fù)制類及其成員跟原始類不產(chǎn)生任何重疊,即我們所說(shuō)的深復(fù)制) ? 看下面代碼:

    ?
  • ICloneable consists of one method: Clone()

  • ?
  • public object Clone()

  • {

  • ?
  • }

  • ?
  • Here's how we'll implement it in the Shoe class:

  • ?
  • public class Shoe : ICloneable

  • {

  • public string Color;

  • #region ICloneable Members

  • ?
  • public object Clone()

  • {

  • Shoe newShoe = new Shoe();

  • newShoe.Color = Color.Clone() as string;

  • return newShoe;

  • }

  • ?
  • #endregion

  • }


  • 在Clone()方法里,我們創(chuàng)建了一個(gè)新的Shoe,克隆所有引用類型變量,復(fù)制所有值類型變量,最后返回新的對(duì)象Shoe。有些既有類已經(jīng)實(shí)現(xiàn)了ICloneable,我們直接使用即可,如String。因此,我們直接使用Color.Clone()。因?yàn)镃lone()返回object對(duì)象,我們需要進(jìn)行一下類型轉(zhuǎn)換。

    下一步,我們?cè)贑opyDude()方法里,用克隆Clone()代替復(fù)制:

    ?
  • public Dude CopyDude()

  • {

  • Dude newPerson = new Dude();

  • newPerson.Name = Name;

  • newPerson.LeftShoe = LeftShoe.Clone() as Shoe;

  • newPerson.RightShoe = RightShoe.Clone() as Shoe;

  • ?
  • return newPerson;

  • }


  • 再次執(zhí)行主方法Main():

    ?
  • public static void Main()

  • {

  • Class1 pgm = new Class1();

  • ?
  • Dude Bill = new Dude();

  • Bill.Name = "Bill";

  • Bill.LeftShoe = new Shoe();

  • Bill.RightShoe = new Shoe();

  • Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";

  • ?
  • Dude Ted = Bill.CopyDude();

  • Ted.Name = "Ted";

  • Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";

  • ?
  • Console.WriteLine(Bill.ToString());

  • Console.WriteLine(Ted.ToString());

  • ?
  • }


  • 我們得到了期望的結(jié)果:

    ?

    Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot


    下面是圖解:

    ?

    整理我們的代碼

    ?

    在實(shí)踐中,我們是希望克隆引用類型并復(fù)制值類型的。這會(huì)讓你回避很多不易察覺(jué)的錯(cuò)誤,就像上面演示的一樣。這種錯(cuò)誤有時(shí)不易被調(diào)試出來(lái),會(huì)讓你很頭疼。

    ?

    因此,為了減輕頭疼,讓我們更進(jìn)一步清理上面的代碼。我們讓Dude類實(shí)現(xiàn)IConeable代替使用CopyDude()方法:

    ?
  • public class Dude: ICloneable

  • {

  • public string Name;

  • public Shoe RightShoe;

  • public Shoe LeftShoe;

  • ?
  • public override string ToString()

  • {

  • return (Name + " : Dude!, I have a " + RightShoe.Color +

  • " shoe on my right foot, and a " +

  • LeftShoe.Color + " on my left foot.");

  • }

  • #region ICloneable Members

  • ?
  • public object Clone()

  • {

  • Dude newPerson = new Dude();

  • newPerson.Name = Name.Clone() as string;

  • newPerson.LeftShoe = LeftShoe.Clone() as Shoe;

  • newPerson.RightShoe = RightShoe.Clone() as Shoe;

  • ?
  • return newPerson;

  • }

  • ?
  • #endregion

  • }


  • 在主方法Main()使用Dude.Clone():

    ?
  • public static void Main()

  • {

  • Class1 pgm = new Class1();

  • ?
  • Dude Bill = new Dude();

  • Bill.Name = "Bill";

  • Bill.LeftShoe = new Shoe();

  • Bill.RightShoe = new Shoe();

  • Bill.LeftShoe.Color = Bill.RightShoe.Color = "Blue";

  • ?
  • Dude Ted = Bill.Clone() as Dude;

  • Ted.Name = "Ted";

  • Ted.LeftShoe.Color = Ted.RightShoe.Color = "Red";

  • ?
  • Console.WriteLine(Bill.ToString());

  • Console.WriteLine(Ted.ToString());

  • ?
  • }


  • 最后得到期望的結(jié)果:

    Bill : Dude!, I have a Blue shoe on my right foot, and a Blue on my left foot. Ted : Dude!, I have a Red shoe on my right foot, and a Red on my left foot.

    ?

    特殊引用類型String

    ?

    在C#中有趣的是,當(dāng)?System.String 使用操作符“=”時(shí),實(shí)際上是進(jìn)行了克隆(深復(fù)制)。你不必?fù)?dān)心你只是在操作一個(gè)指針,它會(huì)在內(nèi)存中創(chuàng)建一個(gè)新的對(duì)象。但是,你一定要注意內(nèi)存的占用問(wèn)題(譯外話:比如為什么在一定情況下我們使用StringBuilder代替String+String+String+String...前者速度稍慢初始化耗多點(diǎn)內(nèi)存但在大字符串操作上節(jié)省內(nèi)存,后者速度稍快初始化簡(jiǎn)單但在大字符串操作上耗內(nèi)存)。如果我們回頭去看上面的圖解中,你會(huì)發(fā)現(xiàn)Stirng類型在圖中并不是一個(gè)針指向另一個(gè)內(nèi)存對(duì)象,而是為了盡可能的簡(jiǎn)單,把它當(dāng)成值類型來(lái)演示了。

    ?

    總結(jié)

    ?

    在實(shí)際工作中,當(dāng)我們需要復(fù)制引用類型變量時(shí),我們最好讓它實(shí)現(xiàn)ICloneable接口。這樣可以讓引用類型模仿值類型的使用,從而防止意外的錯(cuò)誤產(chǎn)生。你可以看到,慎重得理不同的類型非常重要,因?yàn)橹殿愋秃鸵妙愋驮趦?nèi)存中的分配是不同的。

    ?

    ?

    翻譯:?http://www.c-sharpcorner.com/UploadFile/rmcochran/chsarp_memory401152006094206AM/chsarp_memory4.aspx

    總結(jié)

    以上是生活随笔為你收集整理的【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第五节 引用类型复制问题及用克隆接口ICloneable修复的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。