Arhn - архитектура программирования

Десериализация файлов BinaryFormatter с более ранней версией приводит к SerializationException.

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

System.Runtime.Serialization.SerializationException was unhandled
Message=The ObjectManager found an invalid number of fixups. This usually     indicates a problem in the Formatter.
Source=mscorlib
StackTrace:
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
   at Microsoft.Samples.TestV1.Main(String[] args) in c:\Users\andrew\Documents\Visual Studio 2013\Projects\vts\CS\V1 Application\TestV1Part2\TestV1Part2.cs:line 29
   at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
...

Это связано с попыткой десериализовать объекты, которые были изменены (добавлены члены) в более поздних версиях с более старой версией. Однако Microsoft заявляет, что это должно работать из-за VTS. См.: https://msdn.microsoft.com/en-us/library/ms229752(v=vs.110).aspx

Они предоставляют пример, который без изменений действительно позволяет вам десериализовать более поздние классы с более старой версией. См.: https://msdn.microsoft.com/en-us/library/7a6c3wzt(v=vs.110).aspx

Однако, как указано здесь: Обратная совместимость десериализации с комментарием,

kareph, what is the real type of Zoo ? I remember some types (arrays) just didn't work right.

– не нужно многого, чтобы сделать вещи несовместимыми. Я взял пример Microsoft VTS (указанный выше) и добавил следующее в пример V2 ApplicationCS в классе «Person»:

[OptionalField(VersionAdded = 2)]
    private List<HealthData> _healthDataList;
 public List<HealthData> HealthDataList
    {
        get { return _healthDataList; }
        set { _healthDataList = value; }
    }

HealthData просто определяется как:

[Serializable]
public class HealthData
{
    #region Fields
    private int _weight;

    private int _height;
    #endregion

    #region Properties
    public int Weight
    {
        get { return _weight; }
        set { _weight = value; }
    }

    public int Height
    {
        get { return _height; }
        set { _height = value; }
    }
    #endregion
}

Этого достаточно, чтобы получить страшное исключение "...недопустимое количество исправлений...".

Любопытно, что если я просто добавлю список целых чисел, все будет хорошо. Мои вопросы:

  1. Что приводит к сбою десериализации? Насколько сложной может быть структура класса, прежде чем что-то пойдет не так? По-видимому, достаточно иметь класс со списком объектов, определяемых пользователем. Что еще?
  2. Как я могу все исправить? Есть ли способ? Было бы неплохо узнать, что мы можем добавлять новых членов и иметь возможность читать новые сериализованные файлы со старыми копиями программного обеспечения.
  3. Этот пост: Обратная совместимость десериализации предлагает proto-buf.net в качестве альтернативы. Будет ли это решать проблему, которую я изложил здесь? Есть ли у него ограничения?

Фактическая структура моего класса немного сложнее, чем в примере с Microsoft, но у меня, безусловно, есть классы Arrays и Lists‹>, так что это неплохо рассмотреть в первую очередь. Но могут быть и другие «подводные камни», которых нет в простом примере Microsoft.

Любые идеи или помощь будут высоко оценены.

Дэйв


Ответы:


1

Я недавно столкнулся с подобной проблемой, и я не мог найти упоминания об этих "подводных камнях"

Десериализация не выполняется по следующей причине:

ObjectManager имеет другую логику для разрешения зависимостей для массивов и для ссылочных типов и типов значений.

Вы добавили массив нового ссылочного типа, которого нет в вашей сборке (он у вас помечен как вторая версия)

Когда ObjectManager пытается разрешить зависимости, он строит график

Когда он видит массив, он не может сразу исправить его, поэтому создает фиктивную ссылку, а затем исправляет массив позже.

И так как этого типа нет в сборке, зависимости не могут быть разрешены. Почему-то не удаляет массив из списка элементов для фиксов и в конце выкидывает исключение "IncorrectNumberOfFixups"

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

Есть три способа контролировать процесс сериализации, в зависимости от того, можете ли вы вносить изменения в старый код или нет:

  1. Использовать привязку сериализации

  2. Используйте суррогаты сериализации

  3. Используйте ISerialization. Подходит, если вы не можете вносить изменения в старый код и в старом коде у вас не контролировался процесс сериализации

Вы можете использовать простое решение, но это не очень хорошо. Реализуйте ISerializable и напишите, что ваш массив новых классов сериализован не как массив классов, а просто как последовательность элементов вне массива

Значит будет корректно работать на старой версии программы

Полезное примечание:

Кроме того, вы можете исправить это, используя второй метод, просто используйте массив структур или используйте Словарь, чтобы каждый элемент Словаря был структурой

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

[Serializable]
class NewItem
{
    public string Name;
}

[Serializable]
class Item : ISerializable
{
    [OptionalField]
    private List<NewItem> _newItems;

    public List<NewItem> NewItems
    {
        get { return _newItems; }
        set { _newItems = value; }
    }

    public Item()
    {

    }

    protected Item(SerializationInfo info, StreamingContext context)
    {
        var newItemsSize = (int)info.GetValue("_newItemsSize", typeof(int));
        _newItems = new List<NewItem>(newItemsSize);
        for (int i = 0; i < newItemsSize; i++)
        {
            var item = (NewItem)info.GetValue($"_newItem{i}", typeof(NewItem));
            _newItems.Add(item);
        }
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("_newItemsSize", _newItems.Count, typeof(int));
        for (int i = 0; i < _newItems.Count; i++)
            info.AddValue($"_newItem{i}", _newItems[i], typeof(NewItem));
    }
}
23.10.2016
Новые материалы

Коллекции публикаций по глубокому обучению
Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

Представляем: Pepita
Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

Советы по коду Laravel #2
1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

3 способа решить квадратное уравнение (3-й мой любимый) -
1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

Создание VR-миров с A-Frame
Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

Демистификация рекурсии
КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..