前言
今天重新看了下關於clr基元型別的東西,覺得還是有必要將其記錄下來,畢竟這是理解clr成功
之路上的重要一步,希望你也和我一樣。
基元型別
編譯器直接支援的資料型別稱之為基元型別,針對那些程式設計師自定義的型別而言。所有基元型別
直接對映到fcl(framework class library)中存在的型別;比如c#中int直接對映到system.
int32型別,且在編譯為il(中間語言)時,他們將會是一模一樣的:
int a=0;system.int32 a=0
;int a=new
int();
system.int32 a=new system.int32();
至於,為什麼我們經常使用的是int這樣的簡單型別,而不是system.int32,微軟在c#語言規範
(cls)中有這樣的建議:「從風格上說,最好是使用關鍵字,而不是使用完整的系統型別名稱」。
但是使用關鍵字有時候會使得程式設計師倍感迷惑,例如int比較沒有int32那樣直接的顯示這是乙個有
符號的32值。
引用型別
任何稱之為「類」的型別都是引用型別。引用型別總是從堆上分配記憶體,c#的new操作符將會返回對
象的記憶體位址。使用引用型別時必須考慮以下事實;
很明顯,過多的使用引用型別可能會導致應用程式效能顯著下降。
引用型別變數的互相賦值只會賦值物件的記憶體位址,所以指向同一物件的變數在發生改變時實際上影
響的是同乙個物件。
值型別
所有值型別又都稱之為結構
型system.valuetye,而後者本身又直接從system.object派生。所有值型別都是密封的(sealed)
,因此,無法被繼承,從而無法使用值型別定義新的型別。
值型別變數的互相賦值將會執行一次逐字段的複製。
值型別與引用型別的取捨
將資料型別定義為結構(值型別)需要考慮一下幾點:
無法繼承和派生是值型別的顯著特點,你必須慎重考慮他們。另外,若值型別例項過大,在入參時會
發生複製行為,占用空間;在作為返回值時也將值型別的例項複製到呼叫者的分配記憶體中。因為未裝箱
的值型別沒有同步索引塊,所以不能使用monitor或lock等方法(語句)讓多個執行緒同步對這個物件的
訪問。裝箱與拆箱
值型別有兩種表現形式:未裝箱(unboxed)和已裝箱(boxed)形式;引用型別總是處於已裝箱模
式。值型別是一種「輕型」的型別,它不會作為物件在託管堆中分配記憶體,不會被垃圾**,也不能通過指標
來引用。但在許多情況下我們需要獲取對乙個值型別例項的引用:
structpoint
arraylist list=new
arraylist();
point p;
for(int i=0;i<5;i++)
上面的例子中,由於arraylist的add方法需要乙個型別為objec的入參,而我們傳入的是值型別point
,所以這裡將發生裝箱的操作。所有在值型別轉化為引用型別的地方都需要裝箱。裝箱(boxing)內部
發生的過程如下:
1.在託管堆上分配好記憶體,大小為值型別所有欄位的大小加上引用型別的額外
成員(物件指標和同步塊索引)
2.值型別的字段複製到新的堆記憶體中
3.返回物件的位址
可見,已裝箱的值型別的生命週期超過了未裝箱的值型別。
另外,值型別在轉化為某個介面或呼叫未重寫的基類方法時(所有的值型別都繼承system.object),需
要裝箱。因為基類的this希望接受乙個指向堆上的乙個物件的指標。
拆箱並不是裝箱的逆過程:
point p=(point)list[0];
拆箱在clr中分兩步完成這個操作:
1.獲取已裝箱的point物件中的各個point欄位的位址,這個過程就是拆箱(unboxing);
2.將這些字段包含的值從堆中複製到基於棧的值型別例項中(也就是上例中的p)。
所以,拆箱實際上是指乙個定址的過程,拆箱的代價遠低於裝箱,因為它確實知識乙個簡單的尋找指標
的過程而已,在這之後才會發生逐字段複製的過程。
基元型別 引用型別和值型別
編譯器直接支援的資料型別稱為基元型別 primitive type 基元型別直接對映到framework類庫 fcl 中存在的型別。fcl型別在c 中對應的基元型別 c 基元型別 fcl型別 是否符合cls 說明 sbyte system.sbyte 否 有符號8位值 byte system.byt...
第五章 基元型別引用型別和值型別
checked開啟時,如果發生溢位會丟擲異常,unchecked則不會排除異常。編譯器預設是關閉溢位檢查的unchecked。若要開啟溢位檢查,使用 checked 在vs的專案屬性中也可設定開啟與否。也可以給一段 新增這樣的標記。如果這段 中呼叫了另外乙個方法,這個方法是不受這個標記控制的。sys...
第5章 基元型別 引用型別與值型別 (2)
所有的值型別都繼承自system.valuetype,而system.valuetype繼承自system.object。它重寫了system.object中的equals方法和gethashcode方法。當定義自己的值型別時我們也應重寫equals方法和gethashcode方法,為它們提供乙個顯...