天天看點

C#裝箱和拆箱

  都知道C#有裝箱和拆箱的操作,聽聞也都是講int類型轉換成object類型就是裝箱,将object類型再轉回int類型就是拆箱。

  

C#裝箱和拆箱

  描述的通俗點:

  裝箱 将值類型轉換成引用類型,

  拆箱 将引用類型轉換成值類型。

  那看來是要先了解一下引用類型和值類型了。

  在C#中,所有稱之為"類(class)"的類型,都是引用類型,而值類型都是标注為結構(struct)或者枚舉(enum)。

  下面就來看一看引用類型和值類型,在執行個體化的時候發生了什麼操作(首先自然是申明一下兩種類型了):

C#裝箱和拆箱

  執行個體化了一個引用類型(SomeRef)和一個值類型(SomeVal),在調用的時候看看會發生什麼:

   

C#裝箱和拆箱
C#裝箱和拆箱

  上述代碼執行完,可以看到在C#在操作引用類型的時候會執行以下幾步

    1.在托管堆上配置設定一塊記憶體;

    2.在配置設定的對象中,還需要加一些額外成員(類型對象指針,同步索引塊),這些成員必須初始化

    3.對象中的字段要初始化為0,(本例中在執行someRef.x = 5時,将字段x改為5)  

    4.在托管堆上配置設定一個對象時,可能會執行一次垃圾收集操作

  看完引用類型,接下來看一下值類型:

C#裝箱和拆箱
C#裝箱和拆箱

  可以看到相對于引用類型,值類型直覺的地方感覺就輕便了許多,

    1.線上程棧上配置設定一塊記憶體

    2.字段就在對象本身(沒有額外的成員,也不包含指向執行個體的指針)

    3.值類型執行個體不受垃圾回收期控制,減少了應用程式在生存周期内進行垃圾回收的次數

  上面對值類型和引用類型做了個初步的解釋

  下面來看看什麼情況下會進行裝箱和拆箱

  現在假設我們需要将一組坐标點存到ArrayList集合中,以便後續的步驟使用,那麼我們會像下面這樣:

  1.定義一個表示坐标的值類型,裡面分别有字段x(橫坐标),字段y(縱坐标)

C#裝箱和拆箱

  2.将幾個點存入ArrayList集合中

    

C#裝箱和拆箱

   通過上例可以看到,通過調用ArrayList的Add方法,将Point坐标點添加到集合中

C#裝箱和拆箱

  這是ArrayList的Add方法原型,可以看到他的接受參數是一個object類型

C#裝箱和拆箱

  但是object類型是由"類(class)"來聲明的,前面說到聲明為"類(class)"的類型都是引用類型,但是我們的Point聲明為"結構(struct)"是一個值類型

  可以看出,傳入的值類型會轉變為引用類型。 

  C#中為了讓一個值類型轉換成一個引用類型,需要進行一次裝箱操作,下面看一下裝箱操作具體會發生哪些事情:

    1.在托管堆上配置設定記憶體

    2.值類型的所有字段複制到新配置設定托管堆記憶體上

    3.傳回對象的位址(這個位址是對一個對象的引用,值類型現在是一個引用類型)

    注:舊的point對象不變,值類型轉換成引用類型的本質是重建立立了一個已裝箱的Point對象(引用類型)

  談完裝箱,再來談一談拆箱

  在上述的坐标點集合對象中,想要擷取第一個點的資訊

C#裝箱和拆箱

  現在知道ArrayList存的都是對象的引用(或指針),那要做的就是擷取元素0中包含的引用(或指針),并将它放到Point對象的執行個體pFirst中

  來看看拆箱的過程,完成了那些事情

    1.擷取已裝箱Point對象中的字段位址

    2.将這些字段的值從托管堆中複制聲明的Point對象執行個體pFirst中(pFirst是值類型,線上程棧中配置設定記憶體)

  目前在C#中,肯定不會再繼續用ArrayList來存儲一些對象的集合了,因為有了一組新的泛型集合,

  例如用List<T>

C#裝箱和拆箱

  在使用的就是就規定是什麼類型,在存取資料的時候,不需要再進行多餘的裝箱和拆箱操作

  但是在寫代碼的時候還是會隐藏很多拆箱和裝箱的過程,注意盡量避免裝箱和拆箱的操作,如果不可避免,那就盡量減少裝箱和拆箱的操作,可以檢視下方簡單示例(無實際意義):

C#裝箱和拆箱

本文來自部落格園,作者:醜萌氣質狗,轉載請注明原文連結:https://www.cnblogs.com/choumengqizhigou/p/10474749.html

轉載請注明出處QQ群:560611514