CLR 基元型別 引用型別和值型別

2022-03-07 18:57:30 字數 2532 閱讀 3802

前言

今天重新看了下關於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

,因此,無法被繼承,從而無法使用值型別定義新的型別。

值型別變數的互相賦值將會執行一次逐字段的複製。

值型別與引用型別的取捨

將資料型別定義為結構(值型別)需要考慮一下幾點:

無法繼承和派生是值型別的顯著特點,你必須慎重考慮他們。另外,若值型別例項過大,在入參時會

發生複製行為,占用空間;在作為返回值時也將值型別的例項複製到呼叫者的分配記憶體中。因為未裝箱

的值型別沒有同步索引塊,所以不能使用monitorlock等方法(語句)讓多個執行緒同步對這個物件的

訪問。裝箱與拆箱

值型別有兩種表現形式:未裝箱(unboxed)和已裝箱(boxed)形式;引用型別總是處於已裝箱模

式。值型別是一種「輕型」的型別,它不會作為物件在託管堆中分配記憶體,不會被垃圾**,也不能通過指標

來引用。但在許多情況下我們需要獲取對乙個值型別例項的引用:

struct

point

arraylist list=new

arraylist();

point p;

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

上面的例子中,由於arraylistadd方法需要乙個型別為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方法,為它們提供乙個顯...