Десериализация объекта после изменений в его структуре - CodeHelper

Десериализация объекта после изменений в его структуре

2

Скажем, у меня есть некоторый класс, который сериализуется в xml-документ. После чего структура класса по какой-либо причине должна измениться. Но так же необходимо сохранить возможность загрузки из xml-документов старого формата. Какие решения данной проблемы существуют? Конвертация старых документов в новый формат?

Лучший ответ:

1

Можно использовать XSLT для преобразования всех вариантов старых форматов к новому. То есть, для каждай новой версии создается файл, описывающий преобразования, которые необходимо произвести для конвертации xml предыдущей версии к текущей. Таким образом, если нужно конвертировать файл версии 2 к текущей версии 5, то необходимо выполнить цепочку преобразований 2->3->4->5, где каждое преобразование осуществляется соответствующим XSLT-файлом.

Новые ответы


0

В MSDN описано понятие Version Tolerant Serialization (VTS), которое обозначает сериализацию, «терипимую» к изменению версии.

Version Tolerant Serialization — это набор фич, включенных в .NET Framework 2.0, которые облегчают внесение изменений в сериализуемые классы. VTS доступно для классов, помеченных атрибутом SerializableAttribute. Благодаря VTS можно добавлять новые поля к классам без нарушения совместимости с сериализованными данными предыдущих версий. Фичи VTS работают когда используется BinaryFormatter и частично работают для SoapFormatter.

В частности VTS позволяет добавить свойства в класс и при этом:

  1. старые версии приложения смогут работать с новой версией сериализованного класса, игнорируя неизвестное поле (Tolerance of Extraneous or Unexpected Data).
  2. новые версии приложения смогут десериализовать старые классы, задавая пропущенным свойствам значения по умолчанию (Tolerance of Missing Data).

Пункт 1 работает из коробки, а вот для пункта 2 нужно пометить соответствующее поле атрибутом OptionalFieldAttribute:

[Serializable]
public class Customer
{
    public string FirstName;

    public string LastName;

    [OptionalField]
    public string Country;
}

Атрибут OptionalFieldAttribute имеет свойство VersionAdded, которое хранит порядковый номер версии файла (начиная с 2). Каждый раз при добавлении нового свойства в класс нужно помечать это поле атрибутом OptionalFieldAttribute и указывать версию изменения.

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

  • OnDeserializingAttribute — отмечается метод, который будет вызван перед десериализацией;
  • OnDeserializedAttribute — отмечается метод, который будет вызван после десериализацией;
  • OnSerializingAttribute — отмечается метод, который будет вызван перед сериализацией;
  • OnSerializedAttribute — отмечается метод, который будет вызван после сериализацией;

Пример использования:

[Serializable]
public class Customer
{
    public string FirstName;

    public string LastName;

    [OptionalField]
    public string Country;

    [OnDeserializing]
    private void ResetCountry (StreamingContext sc)
    {
        Country = "Россия";
    }
}

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

1

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

  1. Добавлению/удалению полей и свойств
  2. Изменению названий пространств имен и перемещению кода из одного пространства имен в другое.
  3. Изменению типов свойств и полей

Но это не является ответом на вопрос об организации процесса загрузки новой структуры из старых xml-файлов.


v1.7.123.556
© 2009—2010 CodeHelper FAQ | О сайте | Обратная связь | История изменений | Статьи
Creative Commons LicenseМатериалы сайта распространяются под лицензией Creative Commons Attribution-Share Alike 3.0 Unported.