Getting the size of a field in bytes with C#

Viewed 52102

I have a class, and I want to inspect its fields and report eventually how many bytes each field takes. I assume all fields are of type Int32, byte, etc.

How can I find out easily how many bytes does the field take?

I need something like:

Int32 a;
// int a_size = a.GetSizeInBytes;
// a_size should be 4
9 Answers

You can't, basically. It will depend on padding, which may well be based on the CLR version you're using and the processor etc. It's easier to work out the total size of an object, assuming it has no references to other objects: create a big array, use GC.GetTotalMemory for a base point, fill the array with references to new instances of your type, and then call GetTotalMemory again. Take one value away from the other, and divide by the number of instances. You should probably create a single instance beforehand to make sure that no new JITted code contributes to the number. Yes, it's as hacky as it sounds - but I've used it to good effect before now.

Just yesterday I was thinking it would be a good idea to write a little helper class for this. Let me know if you'd be interested.

EDIT: There are two other suggestions, and I'd like to address them both.

Firstly, the sizeof operator: this only shows how much space the type takes up in the abstract, with no padding applied round it. (It includes padding within a structure, but not padding applied to a variable of that type within another type.)

Next, Marshal.SizeOf: this only shows the unmanaged size after marshalling, not the actual size in memory. As the documentation explicitly states:

The size returned is the actually the size of the unmanaged type. The unmanaged and managed sizes of an object can differ. For character types, the size is affected by the CharSet value applied to that class.

And again, padding can make a difference.

Just to clarify what I mean about padding being relevant, consider these two classes:

class FourBytes { byte a, b, c, d; }
class FiveBytes { byte a, b, c, d, e; }

On my x86 box, an instance of FourBytes takes 12 bytes (including overhead). An instance of FiveBytes takes 16 bytes. The only difference is the "e" variable - so does that take 4 bytes? Well, sort of... and sort of not. Fairly obviously, you could remove any single variable from FiveBytes to get the size back down to 12 bytes, but that doesn't mean that each of the variables takes up 4 bytes (think about removing all of them!). The cost of a single variable just isn't a concept which makes a lot of sense here.

Depending on the needs of the questionee, Marshal.SizeOf might or might not give you what you want. (Edited after Jon Skeet posted his answer).

using System;
using System.Runtime.InteropServices;

public class MyClass
{
    public static void Main()
    {
        Int32 a = 10;
        Console.WriteLine(Marshal.SizeOf(a));
        Console.ReadLine();
    }
}

Note that, as jkersch says, sizeof can be used, but unfortunately only with value types. If you need the size of a class, Marshal.SizeOf is the way to go.

Jon Skeet has laid out why neither sizeof nor Marshal.SizeOf is perfect. I guess the questionee needs to decide wether either is acceptable to his problem.

if you have the type, use the sizeof operator. it will return the type`s size in byte. e.g.

Console.WriteLine(sizeof(int));

will output:

4

Simplest way is: int size = *((int*)type.TypeHandle.Value + 1)

I know this is implementation detail but GC relies on it and it needs to be as close to start of the methodtable for efficiency plus taking into consideration how GC code complex is nobody will dare to change it in future. In fact it works for every minor/major versions of .net framework+.net core. (Currently unable to test for 1.0)
If you want more reliable way, emit a struct in a dynamic assembly with [StructLayout(LayoutKind.Auto)] with exact same fields in same order, take its size with sizeof IL instruction. You may want to emit a static method within struct which simply returns this value. Then add 2*IntPtr.Size for object header. This should give you exact value.
But if your class derives from another class, you need to find each size of base class seperatly and add them + 2*Inptr.Size again for header. You can do this by getting fields with BindingFlags.DeclaredOnly flag.

System.Runtime.CompilerServices.Unsafe

Use System.Runtime.CompilerServices.Unsafe.SizeOf<T>() where T: unmanaged

(when not running in .NET Core you need to install that NuGet package)

Documentation states:

Returns the size of an object of the given type parameter.

It seems to use the sizeof IL-instruction just as Earlz solution does as well. (source)

The unmanaged constraint is new in C# 7.3

Related