在.NET中一般都是通過sizeof()或Marshal.SizeOf()來獲取數據類型的大小,來簡要地看一下它們二者有何不同。
sizeof()
sizeof()在MSDN中的介紹是,在編譯時獲得一個數據類型的確定大小,並且被指定為一個常量。如果試圖把它用在無效類型上則會出現編譯錯誤,見CS0233。
也就意味着在運行階段它是沒有開銷的。
例子
1 sizeof(int)
編譯成IL則為:
ldc.i4.4
Marshal.SizeOf()
在System.Runtime.InteropServices.Marshal.SizeOf(),MSDN介紹是,總是在運行時計算結構化數據類型的大小。
這就是說,像裝箱或者計算大小的開銷在該方法被調用時。
例子
Marshal.SizeOf<int>()
編譯成IL則為:
call System.Runtime.InteropServices.Marshal.SizeOf<Int32>
一窺究竟
我們可以看看源碼 (referencesource)
1 //==================================================================== 2 // SizeOf() 3 //==================================================================== 4 [ResourceExposure(ResourceScope.None)] 5 [System.Runtime.InteropServices.ComVisible(true)] 6 public static int SizeOf(Object structure) 7 { 8 if (structure == null) 9 throw new ArgumentNullException("structure"); 10 // we never had a check for generics here 11 Contract.EndContractBlock(); 12 13 return SizeOfHelper(structure.GetType(), true); 14 } 15 16 public static int SizeOf<T>(T structure) 17 { 18 return SizeOf((object)structure); 19 } 20 21 [ResourceExposure(ResourceScope.None)] 22 [Pure] 23 public static int SizeOf(Type t) 24 { 25 if (t == null) 26 throw new ArgumentNullException("t"); 27 if (!(t is RuntimeType)) 28 throw new ArgumentException(Environment.GetResourceString("Argument_MustBeRuntimeType"), "t"); 29 if (t.IsGenericType) 30 throw new ArgumentException(Environment.GetResourceString("Argument_NeedNonGenericType"), "t"); 31 Contract.EndContractBlock(); 32 33 return SizeOfHelper(t, true); 34 } 35 36 public static int SizeOf<T>() 37 { 38 return SizeOf(typeof(T)); 39 } 40 41 [ResourceExposure(ResourceScope.None)] 42 [MethodImplAttribute(MethodImplOptions.InternalCall)] 43 internal static extern int SizeOfHelper(Type t, bool throwIfNotMarshalable);
從上面可以看出這個Marshal.SizeOf()方法依賴SizeOfHelper這個外部方法的引用,如果數據類型有提供則在外部執行計算。如果是結構體裝箱為對象,則把該對象當參數傳入。
注意事項
如下Marshal.SizeOf<T>() 與sizeof(T)的一些類型,計算出大小的結果
1 Marshal.SizeOf<Boolean>(): 4 2 sizeof(Boolean): 1 3 Marshal.SizeOf<Char>(): 1 4 sizeof(Char): 2
看這些相同類型下,在.Net中被封送處理成非托管的數據類型時,原托管類型2個字節的Char計算成了Windows系統類型中的1個字節的SBYTE,而托管類型1個字節的Boolean計算成了Windows系統類型中的4個字節的BOOL。
(原文引自:sizeof() vs Marshal.SizeOf())