Каковы недостатки встроенной сериализации .Net на основе BinaryFormatter? - PullRequest
15 голосов
/ 01 апреля 2009

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

Пожалуйста, приложите ваш ответ с кодом, если это возможно.

Пример:

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

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

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

Ответы [ 10 ]

21 голосов
/ 01 апреля 2009

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

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

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

Это:

2 голосов
/ 01 апреля 2009

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

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

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

2 голосов
/ 01 апреля 2009
1 голос
/ 01 апреля 2009

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

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

1 голос
/ 01 апреля 2009

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

1 голос
/ 01 апреля 2009

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

0 голосов
/ 10 апреля 2012

В другой ситуации BinaryFormatter вызывает исключение.

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

[Serializable]
class Data
{
    public int _t;
}

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

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

0 голосов
/ 14 мая 2010

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

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

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

0 голосов
/ 01 апреля 2009

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

* ** 1003 тысяча два * Пример

Время сериализации и десериализации 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 раз.

0 голосов
/ 01 апреля 2009

Типы сериализации должны быть украшен [Сериализуемый] атрибут.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...