What's the difference between sizeof(T) and Unsafe.SizeOf<T>()?
.net, c#, cil, visual-studio
Solution
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);
}
Problem
First of all, a small disclaimer before the actual question: I know there are a lot of closed/duplicate questions regarding the difference between the `sizeof` operator and the `Marshal.SizeOf<T>` method, and I do understand the difference between the two. Here I'm talking about the `SizeOf<T>` method in the new `Unsafe` class So, I'm not sure I understand the actual difference between these two operations, and whether there's a specific difference when using the method on a struct/class in particular. The `sizeof` operator takes a Type name and returns the number of managed bytes it is supposed to take up when allocated (ie. an `Int32` will return 4, for example). The `Unsafe.SizeOf<T>` method on the other hand, is implemented in IL like all the other methods in the `Unsafe` class, and looking at the code here's what it does: ``` .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 } ``` Now, if I'm not wrong, the code is just calling `sizeof !!T` which is the same as `sizeof(T)` (calling the `sizeof` operator with the type name `T`), so wouldn't the two of them be exactly equivalent? Also, I see the method is also allocating a useless object (the `NonVersionableAttribute`) in the first line, so wouldn't that cause a small amount of memory to be heap-allocated as well? My question is: Is it safe to say that the two methods are perfectly equivalent and that therefore it is just better to use the classic `sizeof` operator, as that also avoid the allocation of that attribute in the `SizeOf<T>` method? Was this `SizeOf<T>` method added to the `Unsafe` class just for convenience at this point?