在.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())