Подтвердить что ты не робот

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

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

Пожалуйста, сопровождайте свой ответ с помощью какого-либо кода, если это возможно.

Пример:

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

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

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

4b9b3361

Ответ 1

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

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

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

Это:

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

Другая проблема, которая пришла на ум:

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

Ответ 7

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

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

Ответ 8

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

Пример

Время для сериализации и десериализации 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 раз медленнее, чем выполнение этого вручную. Конечно, в сериализованном потоке есть информация о типе. Но это вряд ли объясняет 20-кратное замедление.

Ответ 9

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

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

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

Ответ 10

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

[Serializable]
class SerializeMe
{
    public List<Data> _dataList;
    public string _name;
}

[Serializable]
class Data
{
    public int _t;
}

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

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