Получение размера поля в байтах с помощью C #

У меня есть class, и я хочу проверить его поля и сообщить, в конце концов, сколько байтов занимает каждое поле. Я предполагаю, что все поля имеют тип Int32, байт и т. Д.

Как я могу легко узнать, сколько байтов занимает поле?

Мне нужно что-то вроде:

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

Вы не можете, в принципе. Это будет зависеть от заполнения, которое может быть основано на используемой версии CLR и процессоре и т. Д. Легче всего определить общий размер объекта, предполагая, что он не имеет ссылок на другие объекты: создать большой массив, используйте GC.GetTotalMemory для базовой точки, заполните массив ссылками на новые экземпляры вашего типа, а затем снова вызовите GetTotalMemory. Отнесите одно значение от другого и разделите на количество экземпляров. Вероятно, вы должны создать один экземпляр заранее, чтобы убедиться, что новый код JIT не внесет свой вклад в число. Да, это так же вредно, как кажется, но я использовал его для хорошего эффекта до сих пор.

Только вчера я подумал, что было бы неплохо написать небольшой вспомогательный class для этого. Дайте мне знать, если вам будет интересно.

EDIT: Есть еще два предложения, и я хотел бы обратиться к ним обоим.

Во-первых, оператор sizeof : это только показывает, сколько пространства занимает тип в абстрактном, без дополнения, применяемого вокруг него. (Он включает вложение в структуру, но не дополнение, применяемое к переменной этого типа внутри другого типа.)

Далее, Marshal.SizeOf : это показывает только неуправляемый размер после сортировки, а не фактический размер в памяти. Поскольку в документации четко указано:

Возвращаемый размер – это фактически размер неуправляемого типа. Неуправляемые и управляемые размеры объекта могут отличаться. Для типов символов размер зависит от значения CharSet, применяемого к этому classу.

И снова прокладка может иметь значение.

Чтобы прояснить, что я имею в виду, когда речь идет о дополнении, рассмотрите эти два classа:

 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 может или не может дать вам то, что вы хотите. (Отредактировано после того, как Джон Скит опубликовал свой ответ).

 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 может использоваться, но, к сожалению, только с типами значений. Если вам нужен размер classа, Marshal.SizeOf – это путь.

Джон Скит изложил, почему ни sizeof, ни Marshal.SizeOf не идеальны. Думаю, что вопросник должен решить, приемлемо ли для его проблемы.

Из рецепта Джона Скетса в его ответе я попытался сделать вспомогательный class, на который он ссылался. Предложения по улучшению приветствуются.

 public class MeasureSize { private readonly Func _generator; private const int NumberOfInstances = 10000; private readonly T[] _memArray; public MeasureSize(Func generator) { _generator = generator; _memArray = new T[NumberOfInstances]; } public long GetByteSize() { //Make one to make sure it is jitted _generator(); long oldSize = GC.GetTotalMemory(false); for(int i=0; i < NumberOfInstances; i++) { _memArray[i] = _generator(); } long newSize = GC.GetTotalMemory(false); return (newSize - oldSize) / NumberOfInstances; } } 

Применение:

Должен быть создан с помощью Func, который генерирует новые экземпляры T. Убедитесь, что тот же экземпляр не возвращается каждый раз. Например, это будет хорошо:

  public long SizeOfSomeObject() { var measure = new MeasureSize(() => new SomeObject()); return measure.GetByteSize(); } 

Это можно сделать косвенно, не учитывая выравнивание. Количество байтов, в которых используется экземпляр ссылочного типа, равно размеру полей полей размера + типа. Поля службы (в 32х занимает 4 байта каждая, 64 х 8 байт):

  1. Sysblockindex
  2. Таблица указателей на методы
  3. + Необязательный (только для массивов) размер массива

Таким образом, для classа без каких-либо полей его экземпляр занимает 8 байтов на 32-кратной машине. Если это class с одним полем, ссылка на один и тот же экземпляр classа, поэтому этот class принимает (64x):

Sysblockindex + pMthdTable + ссылка на class = 8 + 8 + 8 = 24 байта

Если это тип значения, у него нет полей экземпляра, поэтому он принимает только размер своих файлов. Например, если у нас есть структура с одним полем int, то на машине 32x требуется только 4 байта памяти.

Я должен был сварить это вплоть до уровня IL, но я, наконец, получил эту функциональность в C # с очень маленькой библиотекой.

Вы можете получить его (лицензию BSD) на битбакет

Пример кода:

 using Earlz.BareMetal; ... Console.WriteLine(BareMetal.SizeOf()); //returns 4 everywhere I've tested Console.WriteLine(BareMetal.SizeOf()); //returns 8 on 64-bit platforms and 4 on 32-bit Console.WriteLine(BareMetal.SizeOf()); //returns 16 in some places, 24 in others. Varies by platform and framework version ... struct Foo { int a, b; byte c; object foo; } 

В основном, то, что я сделал, это написать краткую оболочку classа-метода вокруг команды sizeof IL. Эта команда получит необработанный объем памяти, которую будет использовать ссылка на объект. Например, если у вас был массив T , то инструкция sizeof сообщит вам, сколько байтов расположено между каждым элементом массива.

Это сильно отличается от оператора sizeof C #. Во-первых, C # допускает только чистые типы значений, потому что на самом деле невозможно получить размер чего-либо еще статическим образом. Напротив, команда sizeof работает на уровне времени выполнения. Таким образом, сколько бы памяти не возвращалась ссылка на тип, используемый во время этого конкретного экземпляра.

Вы можете увидеть дополнительную информацию и немного более подробный образец кода в моем блоге

если у вас есть тип, используйте оператор sizeof. он вернет размер типа в байте. например

Console.WriteLine (SizeOf (INT));

выведет:

4

Вы можете использовать перегрузку метода в качестве трюка для определения размера поля:

 public static int FieldSize(int Field) { return sizeof(int); } public static int FieldSize(bool Field) { return sizeof(bool); } public static int FieldSize(SomeStructType Field) { return sizeof(SomeStructType); } 
  • Печать отладочной информации об ошибках с помощью java 8 lambda-выражений
  • Могу ли я получить имена / значения параметров процедурно из текущей исполняемой функции?
  • Как читать значение частного поля из другого classа в Java?
  • Как вызвать метод Scala Object с использованием отражения?
  • Прочитать значение атрибута метода
  • Как получить доступ к внутреннему classу с помощью Reflection
  • Как получить annotations переменной-члена?
  • Как я могу получить все константы типа путем отражения?
  • Получить имя свойства как строку
  • GetEntryAssembly для веб-приложений
  • Java: доступ к частному конструктору с параметрами типа
  • Давайте будем гением компьютера.