猿问

使用C#获取字段大小(以字节为单位)

使用C#获取字段大小(以字节为单位)

我有一个类,我想检查它的字段并最终报告每个字段占用的字节数。我假设所有字段都是Int32,byte等类型。


如何轻松找出该字段占用的字节数?


我需要这样的东西:


Int32 a;

// int a_size = a.GetSizeInBytes;

// a_size should be 4


慕尼黑5688855
浏览 428回答 3
3回答

皈依舞

基本上你不能。它将取决于填充,这可能基于您正在使用的CLR版本和处理器等。假设它没有引用其他对象,则更容易计算出对象的总大小:创建一个大数组,使用GC.GetTotalMemory作为基点,使用对类型的新实例的引用填充数组,然后再次调用GetTotalMemory。取一个值远离另一个值,除以实例数。您可能应该事先创建一个实例,以确保没有新的JITted代码对该数字有贡献。是的,它听起来像黑客一样 - 但我之前已经用它效果很好。就在昨天,我认为为此编写一个小助手类是个好主意。如果您有兴趣,请告诉我。编辑:还有其他两个建议,我想解决它们。首先,sizeof运算符:这只显示了抽象中类型占用了多少空间,没有应用填充。(它包括结构中的填充,但不是在另一种类型中应用于该类型的变量的填充。)接下来,Marshal.SizeOf:这只显示编组后的非托管大小,而不是内存中的实际大小。正如文档明确指出:返回的大小实际上是非托管类型的大小。对象的非托管和托管大小可以不同。对于字符类型,大小受应用于该类的CharSet值的影响。再次,填充可以有所作为。只是为了澄清我对填充相关的含义,请考虑以下两个类:class FourBytes { byte a, b, c, d; }class FiveBytes { byte a, b, c, d, e; }在我的x86盒子上,一个FourBytes实例需要12个字节(包括开销)。FiveBytes的实例需要16个字节。唯一的区别是“e”变量 - 那么需要4个字节吗?好吧,有点......而不是。很明显,您可以从FiveBytes中删除任何单个变量以将大小缩减到12个字节,但这并不意味着每个变量占用4个字节(考虑删除所有变量!)。单个变量的成本并不是一个在这里很有意义的概念。

一只甜甜圈

根据被问者的需要,Marshal.SizeOf可能会或可能不会给你你想要的东西。(Jon Skeet发布他的回答后编辑)。using System;using System.Runtime.InteropServices;public class MyClass{     public static void Main()     {         Int32 a = 10;         Console.WriteLine(Marshal.SizeOf(a));         Console.ReadLine();     }}请注意,正如jkersch所说,可以使用sizeof,但遗憾的是只能使用值类型。如果你需要一个班级的大小,Marshal.SizeOf就是你要走的路。Jon Skeet已经阐明了为什么sizeof和Marshal.SizeOf都不是完美的。我想问题需要决定是否可以接受他的问题。

ibeautiful

从他在答案中的Jon Skeets食谱中我试图制作他所指的帮助班。欢迎提出改进建议。public&nbsp;class&nbsp;MeasureSize<T>{ &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;Func<T>&nbsp;_generator; &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;const&nbsp;int&nbsp;NumberOfInstances&nbsp;=&nbsp;10000; &nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;readonly&nbsp;T[]&nbsp;_memArray; &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;MeasureSize(Func<T>&nbsp;generator) &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_generator&nbsp;=&nbsp;generator; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_memArray&nbsp;=&nbsp;new&nbsp;T[NumberOfInstances]; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;long&nbsp;GetByteSize() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Make&nbsp;one&nbsp;to&nbsp;make&nbsp;sure&nbsp;it&nbsp;is&nbsp;jitted &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_generator(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;oldSize&nbsp;=&nbsp;GC.GetTotalMemory(false); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;&nbsp;i&nbsp;<&nbsp;NumberOfInstances;&nbsp;i++) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_memArray[i]&nbsp;=&nbsp;_generator(); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;long&nbsp;newSize&nbsp;=&nbsp;GC.GetTotalMemory(false); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;(newSize&nbsp;-&nbsp;oldSize)&nbsp;/&nbsp;NumberOfInstances; &nbsp;&nbsp;&nbsp;&nbsp;}}用法:应该使用生成T的新实例的Func创建。确保每次都不返回相同的实例。这没关系:&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;long&nbsp;SizeOfSomeObject() &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;measure&nbsp;=&nbsp;new&nbsp;MeasureSize<SomeObject>(()&nbsp;=>&nbsp;new&nbsp;SomeObject()); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;measure.GetByteSize(); &nbsp;&nbsp;&nbsp;&nbsp;}
随时随地看视频慕课网APP
我要回答