.NET的基元類型包括什么及Unmanaged和Blittable類型詳解
在討論.NET的類型系統(tǒng)的時(shí)候,我們經(jīng)常提到“基元類型(Primitive Type)”的概念,我發(fā)現(xiàn)很多人并沒(méi)有真正理解基元類型就究竟包含哪些(比如很多人覺(jué)得字符串是基元類型)。除了明確界定基元類型外,本篇文章還會(huì)簡(jiǎn)單介紹額外兩種關(guān)于類型的概念——Unmanaged類型和Blittable類型。
一、Primitive Type
二、Unmanaged Type
三、Blittable Type
一、Primitive Type
.NET下的基元類型(Primitive Type)如下14個(gè)。我們可以這樣來(lái)記:長(zhǎng)度(字節(jié)數(shù))分別為1、2、4、8的有/無(wú)符號(hào)的整數(shù);外加兩個(gè)基于指針寬度(下x86=4; x64=8)的整數(shù),計(jì)10個(gè)。長(zhǎng)度(字節(jié)數(shù))分別為4和8的單精度和雙精度浮點(diǎn)數(shù),計(jì)2個(gè)。外加布爾類型和字符類型, 計(jì)2個(gè)。所以我們熟悉的String(string)和Decimal(decimal)并不是基元類型。
- 整數(shù)(10):Byte(byte)/SByte(sbyte), Int16(short)/UInt16(ushort), Int32(int)/UInt32(uint), Int64(long)/UInt64(ulong), IntPtr(nint)/UIntPtr(nuint)
- 浮點(diǎn)(2):Float(float), Double(double)
- 布爾(1):Boolean(bool)
- 字符(1):Char(char)
對(duì)于某個(gè)指定的Type對(duì)象,我們可以利用它的IsPrimitive屬性確定它是否為基元類型。
public abstract class Type
{
public bool IsPrimitive { get; }
}Type對(duì)象的IsPrimitive屬性值最終來(lái)源于RuntimeTypeHandle類型如下這個(gè)內(nèi)部靜態(tài)方法IsPrimitive。從該方法的實(shí)現(xiàn)和CorElementType的枚舉成員也可以看出,枚舉值2-13,外加CorElementType.I(IntPtr)和CorElementType.U(UIntPtr)這14個(gè)類型屬于基元類型的范疇,這與上面的列表是一致的。
public struct RuntimeTypeHandle
{
[SecuritySafeCritical]
internal static bool IsPrimitive(RuntimeType type)
{
CorElementType corElementType = GetCorElementType(type);
if (((int)corElementType < 2 || (int)corElementType > 13) && corElementType != CorElementType.I)
{
return corElementType == CorElementType.U;
}
return true;
}
}
[Serializable]
internal enum CorElementType : byte
{
End = 0,
Void = 1,
Boolean = 2,
Char = 3,
I1 = 4,
U1 = 5,
I2 = 6,
U2 = 7,
I4 = 8,
U4 = 9,
I8 = 10,
U8 = 11,
R4 = 12,
R8 = 13,
String = 14,
Ptr = 15,
ByRef = 16,
ValueType = 17,
Class = 18,
Var = 19,
Array = 20,
GenericInst = 21,
TypedByRef = 22,
I = 24,
U = 25,
FnPtr = 27,
Object = 28,
SzArray = 29,
MVar = 30,
CModReqd = 31,
CModOpt = 32,
Internal = 33,
Max = 34,
Modifier = 64,
Sentinel = 65,
Pinned = 69
}二、Unmanaged Type
顧名思義,Unmanaged類型可以理解不涉及托管對(duì)象引用的值類型。如下的類型屬于Unmanaged 類型的范疇:
14種基元類型+Decimal(decimal)
枚舉類型
指針類型(比如int*, long*)
只包含Unmanaged類型字段的結(jié)構(gòu)體
如果要求泛型類型是一個(gè)Unmananged類型,我們可以按照如下的方式使用unmanaged泛型約束。我在《如何計(jì)算一個(gè)實(shí)例占用多少內(nèi)存?》提到過(guò),只有Unmananged類型采用使用sizeof操作符計(jì)算大小。
public static unsafe int SizeOf<T>() where T : unmanaged
{
return sizeof(T);
}三、Blittable Type
Blittable是站在基于P/Invoke的互操作(InterOp)角度對(duì)傳遞的值是否需要進(jìn)行轉(zhuǎn)換(Marshaling)而作的分類。Blittable類型要求在托管內(nèi)存和非托管內(nèi)存具有完全一致的表示。如果某個(gè)參數(shù)為Blittable類型,在一個(gè)P/Invoke方法調(diào)用非托管方法的時(shí)候,該參數(shù)就無(wú)需要作任何的轉(zhuǎn)換。與之類似,如果調(diào)用方法的返回值是Blittable類型,在回到托管世界后也無(wú)需轉(zhuǎn)換。如下的類型屬于Blittable類型范疇:
- 除Boolean(bool)和Char(char)之外的12種基元類型,因?yàn)椴紶栔礣rue在不同的平臺(tái)可能會(huì)表示成1或者-1,對(duì)應(yīng)的字節(jié)數(shù)可能是1、2或者4,字符涉及不同的編碼(Unicode和ANSI),所以這兩種類型并非Blittable類型;
- Blittable基元類型的一維數(shù)組;
- 采用Sequential和Explicitly布局的且只包含Blittable類型成員的結(jié)構(gòu)或者類,因?yàn)椴捎眠@兩種布局的對(duì)象最終會(huì)按照一種確定的格式轉(zhuǎn)換成對(duì)應(yīng)的C風(fēng)格的結(jié)構(gòu)體。如果采用Auto布局,CLR會(huì)按照少占用內(nèi)存的原則對(duì)字段成員重新排序,意味著其內(nèi)存結(jié)構(gòu)是不確定的。
順便強(qiáng)調(diào)一下,DateTime/DateTimeOffset都采用Auto布局(如下所示),Guid雖然是一個(gè)默認(rèn)采用Sequential布局的結(jié)構(gòu)體,但是最終映射在內(nèi)存種的字節(jié)依賴于字節(jié)序(Endianness),所以具有這三種類型字段的結(jié)構(gòu)體或者類都不是Blittable類型。
[Serializable]
[StructLayout(LayoutKind.Auto)]
public struct DateTime
{ }
[Serializable]
[StructLayout(LayoutKind.Auto)]
public struct DateTimeOffset
{ }只有Blittable類型的實(shí)例才能調(diào)用GCHandle的靜態(tài)方法Alloc為其創(chuàng)建一個(gè)Pinned類型的GC句柄。以如下的代碼為例,類Foobar的兩個(gè)屬性都是Blittable類型,我們通過(guò)標(biāo)注在類型上的StructLayoutAttribute將布局類型顯式設(shè)置成Sequential使其稱為了一個(gè)Blittable類型。
GCHandle.Alloc(new Foobar(), GCHandleType.Pinned);
[StructLayout(LayoutKind.Sequential)]
public class Foobar
{
public int Foo { get; set; }
public double Bar { get; set; }
}如果Foobar類定義成如下的形式,都不能使其稱為一個(gè)Blittable類型。前者默認(rèn)采用Auto布局,后者的Bar屬性并不是Blittable類型。如果將這樣Foobar對(duì)象作為參數(shù)按照上面的方式調(diào)用GCHandle. Alloc方法,會(huì)直接拋出ArgumentException異常,并提示“Object contains non-primitive or non-blittable data. (Parameter 'value')”。
public class Foobar
{
public int Foo { get; set; }
public double Bar { get; set; }
}
[StructLayout(LayoutKind.Sequential)]
public class Foobar
{
public int Foo { get; set; }
public DateTime Bar { get; set; }
}到此這篇關(guān)于.NET的基元類型包括什么及Unmanaged和Blittable類型詳解的文章就介紹到這了,更多相關(guān).NET的基元類型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
asp.net 在客戶端顯示服務(wù)器端任務(wù)處理進(jìn)度條的探討
由于 HTTP 協(xié)議本身的無(wú)狀態(tài)性,B/S結(jié)構(gòu)的程序無(wú)法像C/S程序那樣,實(shí)時(shí)顯示程序處理的進(jìn)度。搜索一下網(wǎng)上,一般都是采用靜態(tài)變量保存程序執(zhí)行進(jìn)度的方法實(shí)現(xiàn),但是,這種方法是完全錯(cuò)誤的,在并發(fā)的情況下,多個(gè)用戶訪問(wèn)一個(gè)程序,會(huì)造成混亂。2009-09-09
ASP.NET(C#)中操作SQLite數(shù)據(jù)庫(kù)實(shí)例
最近項(xiàng)目中有使用到SQLite數(shù)據(jù)庫(kù),于是查找資料,編寫了一個(gè)ASP.NET基于C#語(yǔ)言的SQLite數(shù)據(jù)庫(kù)操作實(shí)例.大家看代碼就可以看懂了,和以往使用ADO.NET操作SQL數(shù)據(jù)庫(kù)類似.2009-12-12
使用 ServiceStack.Text 序列化 json的實(shí)現(xiàn)代碼
今天發(fā)篇文章總結(jié)下自己使用 ServiceStack.Text 來(lái)序列化 json。它的速度比 Newtonsoft.Json 快很多,在測(cè)試時(shí)發(fā)現(xiàn)比 fastJson 還快些2013-06-06
.net framework中引進(jìn)的var對(duì)象類型聲明
安裝了vs 2008之后,在后臺(tái)代碼中,resharper插件對(duì)后臺(tái)所有局部變量進(jìn)行提示建議,顯示需要采用use implicitly typed local variable declaration,通過(guò)代碼修改建議2010-12-12
.NET高級(jí)調(diào)試之sos命令輸出看不懂的處理方法
.NET高級(jí)調(diào)試屬于一個(gè)偏冷門的領(lǐng)域,國(guó)內(nèi)可觀測(cè)的資料比較少,所以很多東西需要你自己去探究源代碼,然后用各種調(diào)試工具去驗(yàn)證,下面通過(guò)本文給大家分享.NET高級(jí)調(diào)試之sos命令輸出的相關(guān)知識(shí),感興趣的朋友一起看看吧2024-03-03
解析WPF實(shí)現(xiàn)音頻文件循環(huán)順序播放的解決方法
本篇文章是對(duì)WPF實(shí)現(xiàn)音頻文件循環(huán)順序播放的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Visual Studio 2013更新內(nèi)容簡(jiǎn)介
這篇文章主要為大家分享了Visual Studio 2013更新內(nèi)容簡(jiǎn)介,感興趣的小伙伴們可以參考一下2016-05-05
詳解最好的.NET開源免費(fèi)ZIP庫(kù)DotNetZip(.NET組件介紹之三)
本篇文章主要介紹了.NET開源免費(fèi)ZIP庫(kù)DotNetZip組件的介紹,可以實(shí)現(xiàn)對(duì)文件的壓縮和解壓,有興趣的朋友可以了解一下。2016-12-12

