第五章 基元型別引用型別和值型別

2022-02-06 10:08:08 字數 3425 閱讀 8606

checked開啟時,如果發生溢位會丟擲異常,unchecked則不會排除異常。

編譯器預設是關閉溢位檢查的unchecked。若要開啟溢位檢查,使用/checked+.在vs的專案屬性中也可設定開啟與否。

也可以給一段**新增這樣的標記。如果這段**中呼叫了另外乙個方法,這個方法是不受這個標記控制的。

system.decimal不是基元型別,checked和unchecked標記對其無效,如果發生溢位是肯定會丟擲異常的。

system。numberics.biginteger內部使用uint32表示任意大的整數,沒有上限和下限,永遠不會溢位,可能會有記憶體溢位。

引用型別:

指標.多個引用可指向指向同乙個例項.複製時只複製引用.

記憶體必須從託管堆上分配,包含的值型別欄位也在堆上。

堆上分配的每個物件都有一些額外成員,都需要初始化。

物件中的其他位元組(為字段而設)總是設為0.

從託管堆上分配物件時,可能強制執行一次垃圾**。

繼承自object.

值型別:

直接儲存的是值本身。複製時複製成員.相互獨立.

輕量級型別,不受垃圾**器的控制。減少了託管堆的壓力,減少了進行垃圾**的次數。

所有的值型別都是隱式密封的,不能被繼承。

繼承自system。valuetype

c#會確保值型別中的所有欄位都初始化為0.但是如果只宣告乙個值型別而不賦值,編譯器會提示使用了可能未賦值的字段.

值型別在引數傳遞時,傳入和傳出方法,都是複製的,也就是說在方法內的修改不會影響方法外.所以,在使用值型別傳遞引數時,要考慮引數的大小,涉及效能問題.

值型別的equal和gethashcode存在效能問題,如果自定義值型別,應該重寫這兩個方法.

值型別有未裝箱和已裝箱兩種形式,引用型別總是處於已裝箱.

clr控制型別中的字段布局

為了提高效能,clr會按照一種方式排列型別中的字段.system.runtime.interopsercives.strucelayoutattribute可以設定排列布局.

裝箱時發生的事情:

1. 在託管堆中分配記憶體,包括值型別的字段和兩個額外的成員.

2.  值型別的字段複製到新分配的堆記憶體.

3. 返回物件位址.

裝箱之後,新物件和原來的值型別之間是沒有聯絡的了.新物件的是由gc**的.這樣,已裝箱的值型別的生存期超過了未裝箱的值型別的生存期.

system.collections.generic.listsystem.collections.arraylist arraylist.add(object)前者的效率和效能要高於後者,中間少了許多的裝箱和拆箱操作.

拆箱的時候有兩個步驟:生成兩條il指令.

1. 拆箱(獲取已裝箱例項中的字段的位址)

2. 字段複製.

拆箱不是直接將裝箱過程倒過來,代價要低許多.

拆箱的時候要先將其轉型為未裝箱時的值型別.如:

int32 x = 9;

object y = x;

int16 z = (int16)y;

這樣是會丟擲錯誤的.正確的做法是: int16 z = (int16)(int32)y;

大多數方法進行過載唯一的目的就是減少常用值型別的裝箱次數.

由於沒裝修的值型別沒有同步塊索引,所以不能使用monitor型別的各種方法(或者c#的lock)讓多個執行緒對這個例項同步訪問.

呼叫乙個值型別虛方法時,值型別不會被裝箱.如equals,gethashcode,tostring.    呼叫乙個非虛的繼承的方法時(gettype)需要進行裝箱操作.因為這些方法是object(gettype)定義的.

同一性是指看兩個引用是否指向同乙個物件.object.referenceequals能夠達到此效果.

object.equals方法實際實現的是同一性,而不是相等性.

system.valuetype重寫了object的equals方法,進行的是相等性檢查,不是同一性檢查.

hashcode

自定義的型別在重寫equals的方法時候,應該同時重寫gethashcode方法.因為雜湊碼用在hashtable和dictionary中用於索引項,要求兩個物件相等,必須要具有相同的雜湊嗎.dictionary是先獲得key的雜湊碼值,根據這個值確定儲存位置(雜湊桶),在根據key查詢的時候,先獲得key 的雜湊碼,根據雜湊碼查詢(先找到雜湊桶,在桶內找到雜湊碼相同的物件).如果修改了key物件,集合就再也找不到這個物件了,所以應當先刪除,再重新新增.

雜湊**是乙個用於在相等測試過程中標識物件的數值。 它還可以作為乙個集合中的物件的索引。

.net framework 不保證 gethashcode 方法的預設實現以及它所返回的值在不同版本的 .net framework 中是相同的。 因此,在進行雜湊運算時,該方法的預設實現不得用作唯一物件識別符號。

值型別基類的gethashcode方法則使用了反射,效率也比較低。object的gethashcode方法返回的雜湊碼能作為全域性唯一的標識,只是在物件的生命週期中不會變,被垃圾**之後,這個雜湊嗎可能會被分給別的物件.如果乙個型別重寫了gethashcode方法,這個id就不具有唯一性了,可以使用system.runtime.compilerservices.runtimehelpers.gethashcode方法獲取乙個物件唯一性id,即使重寫了gethashcode方法.

**使用dynamic變數或表示式呼叫乙個成員時,編譯器會生成特殊的il描述這樣的操作,稱為payload(有效載荷).根據實際型別決定具體執行的操作.

dynamic型別可以隱式轉換為其他型別,object不可以,如果型別不相容,會丟擲invalidcastexception.

dynamic和var是不一樣的.var是讓編譯器根據表示式推斷具體的資料型別.dynamic是執行的時候決定型別.

com,如excel操作時,excel.cell[1,1]就是dynamic型別excel.cell[1,1].value和((range)excel.cell[1,1]).value效果是一樣的.

dynamic有時候可以簡化反射的**,直接呼叫方法的名字,而不用通過反射找到指定名字的方法,然後呼叫.

但是dynamic型別是需要載入額外的dll的,額外開銷是不容忽視的.所以用的時候需要綜合考慮.

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

編譯器直接支援的資料型別稱為基元型別 primitive type 基元型別直接對映到framework類庫 fcl 中存在的型別。fcl型別在c 中對應的基元型別 c 基元型別 fcl型別 是否符合cls 說明 sbyte system.sbyte 否 有符號8位值 byte system.byt...

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

前言 今天重新看了下關於clr基元型別的東西,覺得還是有必要將其記錄下來,畢竟這是理解clr成功 之路上的重要一步,希望你也和我一樣。基元型別 編譯器直接支援的資料型別稱之為基元型別,針對那些程式設計師自定義的型別而言。所有基元型別 直接對映到fcl framework class library ...

js第五章引用型別

5.2.6陣列的操作方法 concat 基於當前陣列中的所有項建立乙個新陣列,返回的是新陣列。該方法會先建立當前陣列的乙個副本,然後將接收到的引數新增在這個副本的末尾,最後返回新構建的陣列。slice 選取陣列部分項。兩引數,分別是要返回項的起始和結束位置。splice 向陣列的中部插入項。spli...