国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

譯文---C#堆VS棧(Part Three)

2019-11-17 02:27:14
字體:
供稿:網(wǎng)友

譯文---C#堆VS棧(Part Three)

前言

在本系列的第一篇文章《C#堆棧對比(Part Two)》中,介紹了值類型和引用類型在參數(shù)傳遞時(shí)的不同,本文將討論如何應(yīng)用ICloneable接口實(shí)現(xiàn)去修復(fù)引在堆上的用變量所帶來的問題。

本文是系列文章的第三部分。

注:限于本人英文理解能力,以及技術(shù)經(jīng)驗(yàn),文中如有錯誤之處,還請各位不吝指出。

目錄

C#堆棧對比(Part One)

C#堆棧對比(Part Two)

C#堆棧對比(Part Three

C#堆棧對比(Part Four)

拷貝不是復(fù)制那么簡單

  為了更清楚的表達(dá)這個(gè)問題,我們來考察一下堆上的值類型與堆上的引用類型。首先,我們來看看值類型。跟隨如下的類和結(jié)構(gòu)體,我們有一個(gè)包含Name和兩個(gè)Shoe字段的Dude類。我們有一個(gè)CopyDude方法方便我們產(chǎn)生一個(gè)新的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è)引用類型(原本中此處為變量類型,作者已更正)并且Shoe結(jié)構(gòu)體是類的一個(gè)成員,他們都在堆上。

  注:這里體現(xiàn)了值類型是在棧上還是在堆上,完全取決于其聲明時(shí)的地點(diǎn)。

  當(dāng)我們運(yùn)行如下的方法時(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改為引用類型呢?那將就是個(gè)問題,更改如下:

public class Shoe{         public string Color;}

  更改之后再次運(yùn)行代碼,得到的結(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

  紅色的鞋子在另一個(gè)人身上,這明顯是錯的,你能看出這是怎么發(fā)生的嗎?下圖就是內(nèi)存引用示例:

  因?yàn)楝F(xiàn)在我們用Shoe的引用類型代替值類型,并且拷貝引用類型內(nèi)容時(shí)僅僅是拷貝了指針(不是指針真正指向的對象),我們必須做一些額外工作使我們的引用類型的Shoe更符合值類型的行為。

  注:上面這個(gè)例子中當(dāng)Shoe為值類型時(shí),已經(jīng)伴隨Dude的構(gòu)造方法生成了一個(gè)完全獨(dú)立的結(jié)構(gòu)體Shoe對象,所以Bill為藍(lán)色的鞋,Ted為紅色的鞋;當(dāng)Shoe為引用類型時(shí),Shoe僅僅初始化了一次,所以Ted在使用Shoe時(shí),其實(shí)更改的還是唯一初始化一次時(shí)的Shoe的內(nèi)容,所以導(dǎo)致了最后大家都為紅鞋。下文會應(yīng)用深拷貝解決引用類型復(fù)制指針的問題。

  幸運(yùn)的是,我們有一個(gè)ICloneable接口來幫我們解決問題。這個(gè)接口是一個(gè)基本的契約,所有Dudes遵守這個(gè)契約并且規(guī)定如何按順序的復(fù)制避免Shoe Sharing問題。我們所有將被復(fù)制的類應(yīng)該使用ICloneable接口,包括Shoe類。

  ICloneable包括一個(gè)方法:Clone()

下面我們將實(shí)現(xiàn)這個(gè)接口: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內(nèi)部,我們僅僅是New了一個(gè)新的Shoe對象,復(fù)制所有引用類型并且拷貝值類型,然后返回一個(gè)新對象。你可能注意到了String類已經(jīng)實(shí)現(xiàn)了ICloneable接口,所以我們能調(diào)用Color.Clone方法。因?yàn)镃lone返回一個(gè)對象的引用,我們必須在設(shè)置Shoe的顏色之前將類型顯示轉(zhuǎn)換成Shoe類型。

  注:String類型是一種特殊的引用類型,其表現(xiàn)形式類似于值類型,因?yàn)樽址豢筛淖儯绻淖儎t產(chǎn)生一個(gè)新對象,請參考這里。

  下一步,在我們的CopyDude方法中我們需要克隆Shoes代替拷貝。

public Dude CopyDude(){                    Dude newPerson = new Dude();                     newPerson.Name = Name;                     newPerson.LeftShoe = LeftShoe.Clone() as Shoe;                     newPerson.RightShoe = RightShoe.Clone() as Shoe;                      return newPerson;}

  現(xiàn)在我們運(yùn)行主方法:

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

  這就是我們想要的。

將事物包裹起來

  作為一個(gè)練習(xí),我們希望總是克隆引用類型和復(fù)制值類型。(這將降低當(dāng)你調(diào)試程序錯誤時(shí)所購買治療頭疼的阿司匹林的數(shù)量)

  所以,在頭疼降低的情況下,讓我們走的更遠(yuǎn)一些并且讓我們整理下Dude類實(shí)現(xiàn)ICloneable接口方法代替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 }

  我們所要做的僅僅是通過使用Dude.Clone改變Main方法中的內(nèi)容。

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.

  所以一切都很正常。

  有一個(gè)很有意思的地方需要注意,System.String的操作符“=”真是的克隆了字符串,所以你不必?fù)?dān)心重復(fù)的引用。然而你必須注意內(nèi)存膨脹。如果你回頭看看圖示,字符串是引用類型,它真的本應(yīng)該是一個(gè)指向堆的指針,但是簡單起見,它的作用類似于值類型。

總結(jié)

  作為一個(gè)練習(xí),如果我們打算每次都拷貝對象,我們應(yīng)該實(shí)現(xiàn)ICloneable接口。這將確保我們的引用類型有點(diǎn)像模仿值類型的行為。正如你所見到的那樣,記錄我們正在處理的變量是重要的,因?yàn)橐妙愋秃椭殿愋驮趧?chuàng)建內(nèi)存上的區(qū)別。

  在這下一篇文章中,我們將審視一種降低內(nèi)存印記的方式。

  1. 引用類型的拷貝一定要注意是深拷貝,還是簡單的指針復(fù)制的淺拷貝。

  2. System.String類型是特殊的引用類型,實(shí)際作用效果類似于值類型。

  3. 引用類型應(yīng)該實(shí)現(xiàn)ICloneable接口,實(shí)現(xiàn)深拷貝,即對象拷貝而非指針拷貝。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 新兴县| 额敏县| 呼伦贝尔市| 关岭| 高淳县| 太康县| 长岛县| 霍山县| 安图县| 澄江县| 奉化市| 南丰县| 靖安县| 乐陵市| 慈利县| 儋州市| 南丹县| 汶川县| 德阳市| 涡阳县| 玛多县| 平安县| 珠海市| 松溪县| 界首市| 南投县| 卢氏县| 崇文区| 嵊州市| 开封市| 西和县| 清流县| 米林县| 彭阳县| 古交市| 贞丰县| 搜索| 尉犁县| 瓮安县| 万荣县| 馆陶县|