C#: Getting size of a value-type variable at runtime?

I know languages such as C and C++ allow determining the size of data (structs, arrays, variables...) at runtime using sizeof() function. I tried that in C# and apparently it does not allow putting variables into the sizeof() function, but type defintions only (float, byte, Int32, uint, etc...), how am I supposed to do that?

Practically, I want this to happen:

int x;
Console.WriteLine(sizeof(x));   // Output: 4

AND NOT:

Console.WriteLine(sizeof(int)); // Output: 4

I'm sure there's some normal way to get the size of data at runtime in C#, yet google didn't give much help.. Here it is my last hope


Solution 1:

Following on from Cory's answer, if performance is important and you need to hit this code a lot then you could cache the size so that the dynamic method only needs to be built and executed once per type:

int x = 42;
Console.WriteLine(Utils.SizeOf(x));    // Output: 4

// ...

public static class Utils
{
    public static int SizeOf<T>(T obj)
    {
        return SizeOfCache<T>.SizeOf;
    }

    private static class SizeOfCache<T>
    {
        public static readonly int SizeOf;

        static SizeOfCache()
        {
            var dm = new DynamicMethod("func", typeof(int),
                                       Type.EmptyTypes, typeof(Utils));

            ILGenerator il = dm.GetILGenerator();
            il.Emit(OpCodes.Sizeof, typeof(T));
            il.Emit(OpCodes.Ret);

            var func = (Func<int>)dm.CreateDelegate(typeof(Func<int>));
            SizeOf = func();
        }
    }
}

Solution 2:

To find the size of an arbitrary variable, x, at runtime you can use Marshal.SizeOf:

System.Runtime.InteropServices.Marshal.SizeOf(x)

As mentioned by dtb, this function returns the size of the variable after marshalling, but in my experience that is usually the size you want, as in a pure managed environment the size of a variable is of little interest.

Solution 3:

The size of int is always going to be 32 bits. Why would you need to get the size at runtime?

With that said, you could use Marshal.SizeOf(), but that's really intended for unmanaged code only.

I stumbled upon some code that apparently will give you the size of a value type. It uses reflection and would be quite an expensive method call compared to the functionality you wanted to use (sizeof()):

using System;
using System.Reflection;
using System.Reflection.Emit;

...

// GetManagedSize() returns the size of a structure whose type
// is 'type', as stored in managed memory. For any reference type
// this will simply return the size of a pointer (4 or 8).
public static int GetManagedSize(Type type)
{
    // all this just to invoke one opcode with no arguments!
    var method = new DynamicMethod("GetManagedSizeImpl", typeof(uint), new Type[0], typeof(TypeExtensions), false);

    ILGenerator gen = method.GetILGenerator();

    gen.Emit(OpCodes.Sizeof, type);
    gen.Emit(OpCodes.Ret);

    var func = (Func<uint>)method.CreateDelegate(typeof(Func<uint>));
    return checked((int)func());
}