首先,在实际问题之前的一个小免责声明:
我知道有很多关于
中的sizeof
运算符和Marshal.SizeOf<T>
方法之间差异的封闭/重复问题,我确实理解了两者之间的区别。我在这里谈论新SizeOf<T>
类Unsafe
方法
所以,我不确定我是否理解这两个操作之间的实际区别,特别是在结构/类上使用该方法时是否存在特定的差异。
sizeof
运算符采用类型名称并返回分配时应占用的托管字节数(即{{1}例如,将返回4。
另一方面,Int32
方法在IL中实现,就像Unsafe.SizeOf<T>
类中的所有其他方法一样,并在此处查看代码:
Unsafe
现在,如果我没有错,代码只是调用.method public hidebysig static int32 SizeOf<T>() cil managed aggressiveinlining
{
.custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 )
.maxstack 1
sizeof !!T
ret
}
与sizeof !!T
相同(调用名为sizeof(T)
的{{1}}运算符),那么这两个人不是完全相同的吗?
另外,我看到该方法也在第一行中分配了一个无用的对象(sizeof
),所以这不会导致少量的内存被堆分配吗?
我的问题是:
可以肯定地说这两种方法是完全等价的,因此最好使用经典的
T
运算符,因为这样也避免了在NonVersionableAttribute
方法中分配该属性?这个sizeof
方法是否仅为方便起见而添加到SizeOf<T>
类?
答案 0 :(得分:23)
虽然这种方法确实只使用sizeof
IL指令 - 但是常规sizeof
运算符存在差异,因为此运算符不能应用于任意类型:
用于获取非托管类型的字节大小。非托管 types包括表中列出的内置类型 如下,以及以下内容:
枚举类型
指针类型
用户定义的结构,不包含任何结构 作为引用类型的字段或属性
如果您尝试编写Unsafe.SizeOf
的模拟 - 它将无效:
public static int SizeOf<T>()
{
// nope, will not compile
return sizeof(T);
}
因此Unsafe.SizeOf
解除了sizeof
运算符的限制,并允许您对任意类型使用IL sizeof
指令(包括将返回引用大小的引用类型)。
至于你在IL中看到的属性构造 - 这并不意味着将为每个调用实例化属性 - 这只是用于将属性与各种成员相关联的IL语法(在这种情况下是方法)。
示例:
public struct Test {
public int Int1;
}
static void Main() {
// works
var s1 = Unsafe.SizeOf<Test>();
// doesn't work, need to mark method with "unsafe"
var s2 = sizeof(Test);
}
另一个例子:
public struct Test {
public int Int1;
public string String1;
}
static unsafe void Main() {
// works, return 16 in 64bit process - 4 for int, 4 for padding, because
// alignment of the type is the size of its largest element, which is 8
// and 8 for string
var s1 = Unsafe.SizeOf<Test>();
// doesn't work even with unsafe,
// cannot take size of variable of managed type "Test"
// because Test contains field of reference type (string)
var s2 = sizeof(Test);
}