Каковы недостатки встроенной сериализации на основе BinaryFormatter .Net?

Каковы недостатки встроенной сериализации на основе BinaryFormatter .Net? (Производительность, гибкость, ограничения)

При необходимости, пожалуйста, сопровождайте свой ответ.

Пример:

Серийные пользовательские объекты должны быть украшены атрибутом [Serializable] или реализовывать интерфейс ISerializable.

Менее очевидный пример:

Анонимные типы не могут быть сериализованы.

Если вы имеете в виду BinaryFormatter :

  • основанный на полях, является очень нетерпимым вариантом; изменить детали частной реализации, и он ломается (даже просто меняя его на автоматически реализованное свойство )
  • не является кросс-совместимым с другими платформами
  • не очень дружит с новыми полями
  • специфична для сборки (метаданные сжигаются)
  • специфичен для MS / .NET (и, возможно, для версии .NET)
  • не обезвреживается
  • не особенно быстрый или небольшой выход
  • не работает на световых структурах (CF? / Silverlight)
  • имеет удручающую привычку тянуть вещи, которых вы не ожидали (обычно через event s)

Я потратил много времени в этой области, в том числе написание (бесплатную) реализации API-интерфейсов сериализации «протокольных буферов» для .NET; Protobuf-сеть

Это:

  • меньший выход и быстрее
  • кросс-совместимость с другими реализациями
  • растяжимый
  • контрактный
  • обеззараживание
  • независимая assembly
  • является открытым документированным стандартом
  • работает во всех версиях .NET (caveat: не проверен на Micro Framework)
  • имеет крючки для подключения к ISerializable (для удаленного доступа и т. д.) и WCF

Для любого случайного объекта очень сложно доказать, действительно ли он сериализуем .

Управление версиями данных осуществляется через атрибуты. Если вы не беспокоитесь о версировании, то это не проблема. Если это так, это огромная проблема.

Проблема с схемой атрибутов заключается в том, что она работает довольно легко для многих тривиальных случаев (например, добавление нового свойства), но довольно быстро ломается, когда вы пытаетесь сделать что-то вроде замены двух значений enum другим новым значением enum (или любым количество общих сценариев, которые поставляются с долговечными постоянными данными).

Я мог бы найти множество подробностей, описывающих проблемы. В конце концов, писать собственный сериализатор довольно легко, если вам нужно …

Если вы измените объект, который вы сериализуете, все старые данные, которые вы сериализовали и сохранили, сломаны. Если вы храните в базе данных или даже в формате XML, проще преобразовать старые данные в новые.

Не гарантируется, что вы можете сериализовать объекты взад и вперед между различными Frameworks (Say 1.0, 1.1, 3.5) или даже различными реализациями CLR (Mono), опять же XML лучше для этой цели.

Еще одна проблема, которая пришла на ум:

Классы XmlSerializer расположены в совершенно другом месте от общих форматов времени выполнения. И хотя они очень похожи на использование, XmlSerializer не реализует интерфейс IFormatter. У вас не может быть кода, который позволяет просто поменять форматтера сериализации на или во время выполнения между BinaryFormatter, XmlSerializer или настраиваемым форматированием, не перескакивая через некоторые дополнительные обручи.

Сериализованные типы должны быть украшены атрибутом [Serializable].

Если вы имеете в виду переменные в classе, вы ошибаетесь. Публичные переменные / свойства автоматически сериализуются

Несколько менее очевидным является то, что производительность довольно скудна для сериализации объектов.

пример

Время для сериализации и десериализации 100 000 объектов на моей машине:

 Time Elapsed 3 ms Full Serialization Cycle: BinaryFormatter Int[100000] Time Elapsed 1246 ms Full Serialization Cycle: BinaryFormatter NumberObject[100000] Time Elapsed 54 ms Full Serialization Cycle: Manual NumberObject[100000] 

В этом простом примере сериализация объекта с одним полем Int занимает 20 раз медленнее, чем выполнение этого вручную. Конечно, в сериализованном streamе есть информация о типе. Но это вряд ли объясняет 20-кратное замедление.

Я согласен с последним ответом. Производительность довольно плохая. Недавно моя команда кодировщиков завершила преобразование моделирования со стандартного C ++ в C ++ / CLI. В C ++ у нас был механизм ручной работы, который работал достаточно хорошо. Мы решили использовать механизм сериализации, а не переписывать старый механизм устойчивости.
Старое симуляция с объемом памяти от 1/2 до 1 Gig и большинством объектов, имеющих указатели на другие объекты и 1000 объектов во время выполнения, будет сохраняться в двоичном файле размером от 10 до 15 мегабайт в минуту. Восстановление из файла было сопоставимым.
Используя те же файлы данных (работающие бок о бок), текущая производительность C ++ / CLI примерно вдвое превышает C ++, пока мы не сделаем упорство (сериализация в новой версии) Writng занимает от 3 до 5 минут, считая занимает от 10 до 20. Размер файла сериализованных файлов примерно в 5 раз превышает размер старых файлов. В основном мы видим 19-кратное увеличение времени чтения и 5-кратное увеличение времени записи. Это неприемлемо, и мы ищем способы исправить это.

При изучении двоичных файлов я обнаружил несколько вещей: 1. Данные типа и сборки записываются в ясный текст для всех типов. Это пространственно неэффективно. 2. Каждый объект / экземпляр каждого типа имеет parsingную информацию о типе / сборке. Одна вещь, которую мы делали в нашей руке, помогала мечансиму, выписывала известную таблицу типов. Когда мы открывали типы в письменном виде, мы искали его существование в этой таблице. Если он не существует, запись была создана с информацией типа и назначенным индексом. Затем мы передали тип infor как целое число. (тип, данные, тип, данные) Этот «трюк» значительно сократит размер. Для этого может потребоваться дважды выполнить данные, однако процесс «на лету» можно было бы развить, в дополнение к добавлению его к таблице, нажав на stream, если бы мы могли гарантировать порядок ресортации из streamа ,

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

Другая ситуация заставляет BinaryFormatter генерировать исключение.

 [Serializable] class SerializeMe { public List _dataList; public string _name; } [Serializable] class Data { public int _t; } 

Представьте, что SerializeMe сериализуется сегодня. Завтра мы решили, что нам больше не нужен class Data и удалим его. Соответственно, мы модифицируем class SerializeMe для удаления списка. В настоящее время невозможно десериализовать старую версию объекта SerializeMe.

Решение состоит в том, чтобы либо создать собственный BinaryFormatter, чтобы должным образом игнорировать дополнительные classы, либо сохранить class Data с пустым определением (не нужно сохранять элемент List).

Interesting Posts
Давайте будем гением компьютера.