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

首頁 > 學院 > 開發設計 > 正文

【C#】 裝箱 (boxing) 和拆箱 (unboxing)

2019-11-17 02:28:49
字體:
來源:轉載
供稿:網友

【C#】 裝箱 (boxing) 和拆箱 (unboxing)

目錄:

1. 裝箱和拆箱

2. 深入理解裝箱和拆箱

3. int[] to object[],值類型數組到對象數組的轉化

4. 使用泛型減少裝箱和拆箱

1. 裝箱和拆箱

裝箱 就是把“值類型”轉換成“引用類型”;

拆箱 就是把“引用類型”轉換成“值類型”;

首先,我們要弄明白為什么需要裝箱和拆箱。C#的所有類型,包括int、boo等,都繼承自System.Object,但是卻又有值類型和引用類型之分。這時你要問,int是繼承自object類型的,object是引用類型,那為何int不是引用類型而是值類型的呢?這就涉及到裝箱和拆箱的概念了。

我們知道對象是創建在堆上的,它的創建和銷毀必然帶來額外的CPU和內存消耗。如果將int,boo等微小而常用的數據類型都放在堆上創建和銷毀,語言的性能將會被極大的限制,有時甚至是無法忍受的。C#將值類型和引用類型分開,值類型直接在棧中被創建,超過作用域后直接銷毀。當需要值類型成為對象時,使用裝箱操作,讓值類型變為一個引用類型的對象。這樣,我們就可以使用object作為通用的接口統一語言內的一切類型。

拆箱 在MSDN官方文檔里用的是 取消裝箱。事實上拆箱是裝箱的逆操作,也就是說我們只對裝過箱的引用類型(通常是object對象)進行拆箱操作。單純拆箱操作的后果無法設想的。

裝箱和拆箱是C#的核心概念,C#利用其完成類型系統的統一。有了裝箱,任何類型的值都可以視為一個對象。CLR在裝箱時是將值類型包裝到System.Object的內部,再將其存儲到托管堆上。拆箱是從對象中提取值類型。裝箱是隱式的而拆箱是顯示的。

//裝箱 boxingint i = 3 ;  //分配在棧上object o = i ;//隱式裝箱操作,int i 在堆上object b = (object)i ; //顯示裝箱操作//拆箱 unboxingint j = (int) o ;//顯示拆箱(將對象o拆箱為int類型)int k = b ;//error!!, 不能隱式拆箱

拆箱 的操作包括

1,檢查對象實例,以卻確保它是給定值類型的裝箱值。

2,將該值從實例復制到值類型變量中。

下面來看看這個例子:

int i=0;System.Object obj=i;Console.WriteLine(i+","+(int)obj);

其中共發生了3次裝箱和一次拆箱!^_^,看出來了吧?!第一次是將i裝箱,第2次是輸出的時候將i轉換成string類型,而string類型為引用類型,即又是裝箱,第三次裝箱就是(int)obj的轉換成string類型,裝箱!拆箱就是(int)obj,將obj拆箱!!

2. 深入理解裝箱和拆箱

object o = 1 ;

這句話的IL代碼如下:

.locals init (  [0] object objValue  ) //以上三行IL表示聲明object類型的名稱為objValue的局部變量  IL_0000: nop  IL_0001: ldc.i4.s 1 //表示將整型數1放到棧頂  IL_0003: box [mscorlib]System.Int32 //執行IL box指令,在內存堆中申請System.Int32類型需要的堆空間  IL_0008: stloc.0 //彈出堆棧上的變量,將它存儲到索引為0的局部變量中

注意注釋的部分。執行裝箱操作時不可避免的要在堆上申請內存空間,并將堆棧上的值類型數據復制到申請的堆內存空間上,這肯定是要消耗內存和cpu資源的。

object objValue = 4;int value = (int)objValue;

同樣,看看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

拆箱操作的執行過程和裝箱操作過程正好相反,是將存儲在堆上的引用類型值轉換為值類型并給值類型變量。裝箱操作和拆箱操作是要額外耗費cpu和內存資源的,所以在c# 2.0之后引入了泛型來減少裝箱操作和拆箱操作消耗。

3. int[] to object[],值類型數組到對象數組的轉化

我們不能直接把值類型的數組賦值給對象數組,例如:

 int[] array  = new int[] { 0 } ; object[] oiArray = (object[])array;//error!! 不能將int[] 轉換到 object[]
 string[] a={"1","2","3"};
 object[] osArray = a ;//正確,a是引用類型數組,不存在裝箱和拆箱

(object[])a無法將a所有的值類型對象“直接”轉換為引用類型,所以編譯器不會通過這個轉換。可以使用如下的方式達到目的:

  int[] array  = new int[] { 0 } ;  object[] oArray = new object[array.Length];  for(int i =0 ; i< array.Length ; i++)  {     oArray[i] = array[i]; //隱式裝箱  }

4. 使用泛型減少裝箱和拆箱

有時說使用泛型能提高C#程序的性能,有一部分性能的提升是由減少了裝箱和拆箱帶來的。考察下面的代碼:

public class Test{    object _o  ;        public Test(object o)    {_o = o ;    }}public class Test<T>{    T _o ;    public Test(T o)    {        _o = o ;    }}

第一個Test類中沒有使用泛型,如果將一個int類型的值傳入Test,將會引發多次的裝箱和拆箱操作。而泛型類在實例化時已經明確了類型,復制操作時就不會有裝箱和拆箱操作了。

引用:

1. 玉開http://m.survivalescaperooms.com/yukaizhao/archive/2011/10/18/csharp_box_unbox_1.html

2. MSDN https://msdn.microsoft.com/zh-cn/library/yz2be5wk.aspx


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 仁怀市| 隆化县| 禹州市| 渝北区| 渝中区| 隆安县| 义乌市| 青河县| 文昌市| 富裕县| 罗城| 广宗县| 读书| 施甸县| 澄城县| 乐至县| 绥滨县| 普格县| 伊春市| 修水县| 同心县| 滨海县| 涿鹿县| 库尔勒市| 栖霞市| 万山特区| 屯门区| 曲周县| 宁晋县| 钟山县| 芜湖县| 磐安县| 梅河口市| 汝州市| 溧阳市| 江孜县| 如东县| 泉州市| 洛扎县| 大竹县| 西林县|