While this method indeed just uses sizeof
IL instruction – there is a difference with regular sizeof
operator, because this operator cannot be applied to arbitrary types:
Used to obtain the size in bytes for an unmanaged type. Unmanaged
types include the built-in types that are listed in the table that
follows, and also the following:Enum types
Pointer types
User-defined structs that do not contain any
fields or properties that are reference types
If you try to write analog of Unsafe.SizeOf
– it will not work:
public static int SizeOf<T>()
{
// nope, will not compile
return sizeof(T);
}
So Unsafe.SizeOf
lifts restrictions of sizeof
operator and allow you to use IL sizeof
instruction with arbitrary types (including reference types for which it will return size of reference).
As for attribute construct you see in IL – that does not mean attribute will be instantiated for each call – that’s just IL syntax for associating attributes with various members (method in this case).
Examples:
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);
}
Another example:
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);
}