值类型的装箱和拆箱
值類型是比引用類型更“輕型”的一種類型,因為它不需要作為對象在托管堆中分配,不會被垃圾回收,也不通過指針來引用。
static void Main()
{
System.Collections.ArrayList list = new System.Collections.ArrayList();
Point p;//分配一個Point,不在堆中分配。
for (int i = 0; i < 20; i++)
{
p.x = p.y = i;//初始化值類型的成員
list.Add(p);//對值類型進行裝箱,并將引用添加到ArrayList中。C#編譯器會自動的生成對一個值類型的實例進行裝箱所需的IL代碼,C#編譯器檢測到是向一個需要引用類型的方法傳遞一個值類型,所以會自動生成代碼對對象進行裝箱。在運行時,當前存在于Point值類型實例p中的字段會復制到新分配的Point對象中。已裝箱的Point對象(已經是引用類型)的地址會返回給Add方法。Point對象會一直存在于堆中,直到被垃圾回收。Point值類型的變量p可以重用,因為ArrayList根本不知道關于它的任何事情。
? ?Point p1 = (Point)list[0];//拆箱? , ? }
}
List.Add()方法需要一個object參數,Add需要獲取對托管堆上的一個對象的引用(或指針)來作為參數。在代碼中傳遞的是p,是一個值類型,為了使代碼正確工作,Point已經進行了一次裝箱。
對一個值類型的實例進行裝箱操作時發生在內部的事情:
1.在托管堆中分配內存。
2.值類型的字段復制到新分配的堆內存中。
3.返回對象的地址,現在這個地址是對一個對象的引用,值類型現在是一個引用類型。
拆箱發生的事:
1.獲取已裝箱的對象的各個字段的地址。
2.將字段包含的值從堆中復制到基于棧的值類型實例中。
拆箱的代價比裝箱的低得多。拆箱就是獲取一個指針的過程,該指針包含在一個對象中的原始值類型,事實上,指針指向的是已裝箱實例中未裝箱的部分,所以和裝箱不同,拆箱不要求在內存中復制任何字節,往往會緊接著拆箱操作發生一次字段的復制操作。
?
裝箱和拆箱會對應用程序的速度和內存消耗產生不利影響,所以應該注意編譯器在什么時候生成代碼來自動這些操作,并嘗試手動編寫代碼,盡量避免自動生成代碼的情況。
static void Main()
{
Int32 i = 5;
object obj = i;//裝箱
Int16 n = (Int16)obj;//拆箱失敗,拋出InvalidCastException異常。如果引用指向的對象不是所期待的值類型的一個已裝箱實例,就拋出此異常。
Int16 nn = (Int16)(Int32)obj;//先拆箱為正確的類型,在進行轉型。
Int32 d = (Int32)obj;//
Console.ReadKey();
}
在對一個對象進行拆箱時,只能將其轉型為原先未裝箱時的值類型。?
static void Main()
{
Int32 i = 5;
object obj = i;//裝箱
i = 123;
Console.WriteLine(i + "," + (Int32)obj);//發生了多少次裝箱?WriteLine()需要獲取一個String對象,但是當前沒有String對象,所以采取
//某種方式對這些數據進行合并,創建一個String對象。
//為了創建String對象編譯器生成代碼來調用String對象的靜態方法Concat。
//String.Concat方法有幾個重載版本,所有版本的執行操作都是一樣的,不同的是參數數量。
//這里連接3個數據項創建一個字符串,所以編譯器選擇的是
//public static String Concat(object obj0,object obj1,object obj2) 這個版本
//為第一個參數傳遞的是i,i是一個未裝箱的值類型,裝箱。
//obj1是一個String對象的引用。obj3要求一次拆箱操作。然后裝箱。
Console.WriteLine(i.ToString() + "," + obj);//這里沒有裝箱操作。i調用ToString方法,返回一個String,String對象已經是引用類型,所以能直接傳遞給Concat方法,不需要任何裝箱操作
Console.ReadKey();
} ?
看看FCL,會發現許多方法都針對不同的值類型參數進行重載。大多數方法進行重載的唯一目的就是減少常值類型的裝箱操作次數。
未裝箱的值類型比引用類型更“輕型”,歸結于以下兩個原因:
1.值類型不再托管堆上。
2.值類型沒有堆上的每個對象都有的額外成員:一個類型對象指針和同步塊索引。
因為值類型沒有同步塊索引,所以哈,不能使用System.Threading.monitor類型的各種方法,實現不了同步。
在C#中只用使用接口才能修改一個已裝箱的值類型中的字段,詳情見126頁。
轉載于:https://www.cnblogs.com/smailxiaobai/archive/2011/11/23/2260403.html
總結
- 上一篇: [mongodb翻译]选择合适的shar
- 下一篇: android各种权限及说明