sizeof(T)和Unsafe.SizeOf <t>()之间有什么区别?

时间:2017-12-21 10:09:18

标签: c# .net visual-studio cil

首先,在实际问题之前的一个小免责声明:

  

我知道有很多关于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>类?

1 个答案:

答案 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);                        
}