读CLR via C#总结(4) 值类型的装箱和拆箱
值類型是比引用類型更"輕型"的一種類型,因為它們不作為對象在托管堆中分配,不會被垃圾回收,也不通過指針來引用。但在許多情況下,都需要獲取對值類型的一個實例引用。為了將一個值類型轉換成一個引用類型,要使用一個名為裝箱(boxing)的機制。
一,裝箱
裝箱即將一個值類型轉換成一個引用類型,下面是總結對值類型的一個實例進行裝箱時內部發生的事情:
1,在托管堆中分配內存。內存量是值類型的各個字段需要的內存量加上托管堆的所有對象都有的兩個額外成員(類型對象指針和同步塊索引)需要的內存量。
2,將值類型的字段復制到新分配的堆內存。
3,返回對象的地址(或稱指針)。現在,這個地址是對一個對象的引用,值類型現在是一個引用類型。
例如:代碼如下:
namespace ValueTypeDemo2{
//聲明一個值類型
struct Point
{
public int x, y;
}
class Program
{
static void Main(string[] args)
{
ArrayList a = new ArrayList();
Point p;//分配一個Point(不在堆中分配)
for (int i = 0; i < 10; i++)
{
p.x = p.y = i;//初始化值類型中的成員
a.Add(p);//對值類型進行裝箱,并將引用添加到ArrayList中,因為Add()方法需要的是一個Object對象
}
}
}
}
二,拆箱
拆箱實際上就是獲取一個指向包含在一個對象中的原始值類型(數據字段)的指針,往往會緊接著拆箱操作后發生一次字段復制的操作,將堆中的字段復制到基于棧的值類型的實例中。
例如:代碼如下:
CLR實際上分兩步完成這個復制操作:
1,獲取已裝箱的Point對象中的各個Point字段的址,這個過程稱為拆箱(unboxing)。
2,將這些字段包含的值從堆中復制到基于棧的值類型的實例中。注意,這個過程不屬于拆箱的范圍。
下面是一個已裝箱值類型實例在拆箱時內部發生的事情:
1,如果包含"對已裝箱值類型實例的引用"的變量為Null,就拋出一個NullReferenceException異常。
2,如果引用指向的對象不是期待的值類型的一個已裝箱實例,就拋出一個InvalidCastException異常。
3,返回一個指向包含在一個對象中的原始值類型的指針。
下面是一個綜合實例,代碼如下:
namespace ValueTypeDemo3{
//聲明一個值類型
struct Point
{
public int x, y;
}
class Program
{
static void Main(string[] args)
{
Point p;//創建Point的實例,在棧上分配
p.x = p.y = 1;//初始化值類型的成員
object o = p;//對p進行裝箱,o引用已裝箱的實例
p = (Point)o;//對o進行拆箱,將字段從已裝箱的實例中復制到棧變量中
}
}
}
生成的IL代碼如下圖,可以看到程序發生了一次裝箱和一次拆箱:
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的读CLR via C#总结(4) 值类型的装箱和拆箱的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: align=absmiddle 是什么意
- 下一篇: 《碟中谍4:幽灵协议》蓝光1080P 7