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?

Original source