基礎系列(4) C 裝箱和拆箱

2022-02-13 11:45:33 字數 3322 閱讀 1948

裝箱是將值型別轉換為引用型別 ;

拆箱是將引用型別轉換為值型別

值型別:包括原型別(sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、bool、decimal)、列舉 (enum) 、結構 (struct)。

引用型別:包括類、陣列、介面、委託、字串等,我們利用**說明一下:

int n = 10

;

object obj =n;

console.writeline(

"裝箱之前的數字為,裝箱之後的數字為

",n,obj.tostring());//此處為裝箱操作,將數值型別轉換為object型別

int m = (int

)obj;

console.writeline(

"拆箱之前的數字為,拆箱之後的數字為

", obj.tostring(),m);

//此處為拆箱操作,將object型別轉換為數值型別

二 為什麼需要裝箱?一種最普通的場景是,呼叫乙個含型別為object的引數的方法,該object可支援任意為型,以便通用。當你需要將乙個值型別(如int32)傳入時,需要裝箱。 

另一種用法是,乙個非泛型的容器,同樣是為了保證通用,而將元素型別定義為object。於是,要將值型別資料加入容器時,需要裝箱。

裝箱和拆箱雖然滿足了兩隻型別之間的轉換。但是從裝箱的過程中不難看出,每次裝箱時要在堆中new乙個新的物件,當量特別大是肯定會大大影響程式的效率。所以,在應用中,我們應該盡量避免裝箱操作。

我們用**說明裝箱與拆箱的效率:

arraylist list = new arraylist();//

宣告乙個陣列集合

//listlist = new list();

//宣告乙個泛型集合

stopwatch sw = new stopwatch(); //

用於測量執行時間

sw.start();

for (int i = 0; i < 10000000; i++)

sw.stop();

console.writeline(sw.elapsed);

上面的**是裝箱的操作:

下面是普通的操作:

//

arraylist list = new arraylist();

//宣告乙個陣列集合

list list = new list(); //

宣告乙個泛型集合

stopwatch sw = new stopwatch(); //

用於測量執行時間

通過上面我們可以看到裝箱與拆箱的時間對比,了解了裝箱和拆箱的操作,我們可以清楚的明白:裝箱操作會導致資料在堆和棧上進行拷貝,頻繁的裝箱操作會效能損失。而相比而言拆箱過程對效能損耗還是比較小的。

我們先看裝箱時都會發生什麼事情,下面是一行最簡單的裝箱**

object obj = 1;
這行語句將整型常量1賦給object型別的變數obj; 眾所周知常量1是值型別,值型別是要放在棧上的,而object是引用型別,它需要放在堆上;要把值型別放在堆上就需要執行一次裝箱操作。

這行語句的il**如下,請注意注釋部分說明:

locals init (

[0] object

objvalue

) //

以上三行il表示宣告object型別的名稱為objvalue的區域性變數

il_0000: nop

il_0001: ldc.i4.s 9//

表示將整型數9放到棧頂

il_0003: box [mscorlib]system.int32 //

執行il box指令,在記憶體堆中申請system.int32型別需要的堆空間

il_0008: stloc.0

//彈出堆疊上的變數,將它儲存到索引為0的區域性變數中

以上就是裝箱所要執行的操作了,執行裝箱操作時不可避免的要在堆上申請記憶體空間,並將堆疊上的值型別資料複製到申請的堆記憶體空間上,這肯定是要消耗記憶體和cpu資源的。我們再看下拆箱操作是怎麼回事:

請看下面的c#**:

object objvalue = 4

;int value = (int)objvalue;

上面的兩行**會執行一次裝箱操作將整形數字常量4裝箱成引用型別object變數objvalue;然後又執行一次拆箱操作,將儲存到堆上的引用變數objvalue儲存到區域性整形值型別變數value中。

同樣我們需要看下il**:

.locals init (

[0] object

objvalue,

[1] int32 '

value')

//上面il宣告兩個區域性變數object型別的objvalue和int32型別的value變數

il_0000: nop

il_0001: ldc.i4.4//

將整型數字4壓入棧

il_0002: box [mscorlib]system.int32 //

執行il box指令,在記憶體堆中申請system.int32型別需要的堆空間

il_0007: stloc.0

//彈出堆疊上的變數,將它儲存到索引為0的區域性變數中

il_0008: ldloc.0

//將索引為0的區域性變數(即objvalue變數)壓入棧

il_0009: unbox.any [mscorlib]system.int32 //

執行il 拆箱指令unbox.any 將引用型別object轉換成system.int32型別

il_000e: stloc.1

//將棧上的資料儲存到索引為1的區域性變數即value

今天就先說這麼多了,有些知識是參考網路上的,希望我們一起進步!

基礎系列(3)—— 高階資料型別

基礎系列(5)—— c#程式控制語句

c 裝箱和拆箱

c 裝箱和拆箱 概念 裝箱 將值型別轉換為引用型別的過程叫做裝箱 值型別 引用型別 相反,拆箱 將引用型別轉換為值型別 叫做拆箱 引用型別 值型別 裝箱例子 int i 2008 object obj i console.writeline 1 i的值為,裝箱之後的值 i,obj i 927 con...

C 裝箱和拆箱

1 什麼是裝箱和拆箱 裝箱是將值型別轉換為引用型別 拆箱是將引用型別轉換為值型別 2 什麼時候需要裝箱?值型別是高效輕量的型別,因為預設情況下在堆上不包括他們的物件元件,然而,如果我們需要物件元件,這個時候就需要裝箱了。最常見的場景就是 乙個方法你希望能共用,設定的引數型別是object型別 引用型...

C 裝箱和拆箱

值型別例項進行裝箱時的步驟 1 在託管堆中分配記憶體。需要注意的是,由於是將值型別進行引用型別化,因而分配的記憶體空間除了值型別各個欄位所需的記憶體之外,還要加上託管堆所有物件都有的兩個額外成員 型別物件指標和同步塊索引 所需的記憶體。2 將值型別的字段複製到新分配的堆記憶體中。3 返回物件位址,即...