views:

4231

answers:

3

I'm having a class which I want to inspect it's fields, and report eventually how much bytes does each field take. I assume all fields are of types as Int32, byte etc. How can I find out easily how much bytes does the field take?

I need something like:

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

+2  A: 

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

Joachim Kerschbaumer
MSDN:Although you can use the SizeOf method, the value returned by this method is not always the same as the value returned by sizeof. Marshal.SizeOf returns the size after the type has been marshaled whereas sizeof returns thesize as it has been allocated by the CLR, including any padding.
Philip Fourie
Link to MSDN: ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/dv_csref/html/c548592c-677c-4f40-a4ce-e613f7529141.htm
Philip Fourie
+4  A: 

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.

Lasse V. Karlsen
The question says "I want to inspect it's fields, and report eventually how much bytes does each field take. I assume all fields are of types as Int32, byte etc." so I don't think Jon Skeet was thinking of class overhead.
Windows programmer
It's not the class overhead - it's that after marshalling, an object can look very different to how it looks in memory. Marshalling is black magic as far as I'm concerned... but the marshalled size may well be different to the size in memory. I'll edit my answer.
Jon Skeet
I guess only the original poster can determine wether either is acceptable, or not. Revised my answer and wikied it.
Lasse V. Karlsen
+20  A: 

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.

Jon Skeet
Marshall.SizeOf is right. Someone must have voted up this answer on the basis of the answerer instead of the answer. oo oo oo oo oops.
Windows programmer
Marshall.SizeOf is *not* right. Hopefully my edited answer explains why not.
Jon Skeet