Определение сериализованного размера типа .NET и неуправляемой эффективности памяти

Мой вопрос в том, можно ли определить сериализованный размер (в байтах) ссылочного типа.

Вот такая ситуация:

Я использую класс BinaryFormatter для сериализации основных типов .NET, например, например:

[Serializable]
public class Foo
{
 public string Foo1 { get; set; }
 public string Foo2 { get; set; } 
}

Я сериализую каждый элемент в байт [], затем добавляю этот сегмент в конец существующего байта [] и дополнительно добавляя возврат каретки в конце каждого сегмента, чтобы разграничить объекты.

Для десериализации я использую Marshal.ReadByte() следующим образом:

List<byte> buffer = new List<byte>();
for (int i = 0; i < MapSize; i++)
{
 byte b = Marshal.ReadByte(readPtr , i); 
 if (b != delim) // read until encounter a carriage return 
 buffer.Add(b);
 else
 break;
}
readPtr = readPtr + buffer.Count + 1; // incrementing the pointer for the next object
return buffer.ToArray(); 
</byte></byte>

Я считаю, что использование Marshal.Copy() было бы более эффективным, но мне нужно заранее знать длину сериализованного байтового сегмента. Есть ли способ, который я могу надежно вычислить это из типа, который является сериализованным, или общий более эффективный метод, который я могу использовать?

Кроме того, использование возврата каретки в конечном итоге не будет надежным. Поэтому мне интересно, существует ли более стандартный способ разграничения объектов путем настройки моего BinaryFormatter или использования какой-либо другой стандартизированной передовой практики? Например, существует конкретный способ, которым BinaryFormatter ограничивает объекты, если его сериализация говорит, общий список <> ?

3 ответа

Невозможно заранее определить сериализованную длину. Спецификация протокола BinaryFormatter доступна здесь: http://msdn.microsoft.com/en-us/library/cc236844(v=prot.10).aspx

Я избавлю вас от необходимости читать его в ваших целях:

  • Он создан как расширяемый формат. Это позволяет добавлять поля позже и поддерживать некоторую совместимость с предыдущими реализациями. Для ваших целей это означает, что длина сериализованной формы не фиксируется во времени.
  • Это очень хрупкий. Бинарный формат фактически кодирует имена полей в нем. Если вы когда-либо переименуете поле, длина сериализованной формы изменится.
  • Двоичный формат фактически охватывает взаимосвязь между сериализованными кодировками и данными объекта. Один и тот же объект потенциально может быть закодирован несколькими способами, с несколькими различными байтами для вывода (я не буду понимать, почему это написано именно так).

Если вам нужен простой способ сделать что-то, просто создайте массив, который содержит все объекты и сериализует этот единственный массив. Это решает большинство ваших проблем. Все вопросы разграничения различных объектов обрабатываются BinaryFormatter. У вас не будет избыточного копирования памяти. Конечный результат будет более компактным, поскольку BinaryFormatter должен указывать имена полей только один раз за вызов.

Наконец, я могу сказать, что дополнительная копия памяти не является основным источником неэффективности вашей текущей реализации. Вы получаете гораздо большую неэффективность из использования BinaryFormatter отражения и тот факт, что он кодирует имена полей в сериализованном выходе.

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


Использование байта в качестве разделителя для двоичных сериализованных данных - ужасная идея - 13 - вполне допустимое значение, которое может быть частью сериализованных данных, а не только "разделителем".

Префикс каждого блока с размером в байтах вместо этого и прочитайте его в блоках.


Вы можете использовать Marshal.SizeOf, чтобы получить собственный размер структуры. Это работает только для структур, и я советую вам установить атрибут StructLayout.

Я вытащу некоторую информацию из комментариев, потому что это удивительно, но важно:

У CLR есть средства метаданных для исправления собственного макета структуры или класса. В С# это возможно только для структур. Но классы тоже могут быть использованы.

Вы можете бит-**** управляемый тип в байты, если вы укажете SequentialLayout. http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx Это средство не известно, но оно существует, указано и поддерживается. Цитата: "Атрибуты макета класса (AutoLayout, SequentialLayout и ExplicitLayout) определяют, как поля экземпляра класса выложены в памяти."

Посмотрите на перечисление System.Reflection.TypeAttributes. Он также определяет другие атрибуты уровня CLR. С# не дает доступа к ним, но ilasm.exe делает.

licensed under cc by-sa 3.0 with attribution.