Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 16:22
Оценка:
Здравствуйте.

У нас есть класс, который представляет собой настройки, введённые пользователем. Что-то типа такого:
class SettingsContainer
{
  public string Name { get; set; }
  public int Age { get; set; }
  public List<SpecialDay> SpecialDays { get; set; }
  public MySerializableDictionaty<string, string> SomeData { get; set; }
  // ........ тут такого еще пара десятков
}

class SpecialDay
{
  public bool IsRepeating { get; set; }
  public DateTime Date { get; set; }
  public string Name { get; set; }
}
// ... еще несколько подобных классов



Планируется сериализировать в отдельный Xml файл, чтобы у пользователя была возможность иметь хоть десяток таких файлов. Обязательным условием есть следующее:
Все последующие версии приложения обязаны быть совместимыми, т.е. любая новая версия должна читать настройки любой предыдущей версии.

Т.е. надо сделать так, чтобы при переименовании свойства, переименовании класса, изменении типа, добавлении и удалении (это не проблема, как я понимаю) всего этого всё было обратно совместимым.


Какие посоветуете сделать шаги на стадии имплементации этого чуда? Какие будут подводные камни в будущем?


Заранее спасибо всем ответившим по делу.
Re: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 16:39
Оценка: 1 (1)
Здравствуйте, Kore Sar, Вы писали:

KS>Планируется сериализировать в отдельный Xml файл, чтобы у пользователя была возможность иметь хоть десяток таких файлов. Обязательным условием есть следующее:

KS>Все последующие версии приложения обязаны быть совместимыми, т.е. любая новая версия должна читать настройки любой предыдущей версии.
KS>Т.е. надо сделать так, чтобы при переименовании свойства, переименовании класса, изменении типа, добавлении и удалении (это не проблема, как я понимаю) всего этого всё было обратно совместимым.
KS>Какие посоветуете сделать шаги на стадии имплементации этого чуда? Какие будут подводные камни в будущем?
KS>Заранее спасибо всем ответившим по делу.

Ну первое что приходит в голову — а зачем что-то переименовывать? Нет, вы, конечно, можете изменить название самого свойства класса, но при этом просто не нужно менять название элемента в которое это свойство сериализуется.
При измении типов определяйте для новых типов конверсию, т.е. чтобы MyOldType можно было бы привести к MyNewType.
Но это в том случае, если использовать стандартную XML-сериализацию.

Я бы в данном случае сделал сериализатор ручками. Причем сериализация бы происходила по манифесту, описанному в том же XML-формате. Манифест бы тупо маппил ХМЛ-элементы на классы, ХМЛ-атрибуты на св-ва и пр.
В будущей версии можно было бы к примеру *полностью* переделать всю объектную модель настроек, но написать специальный манифест для совместимости, с помощью которого можно было бы грузить старые конфиги.

Плюс не было бы всего этого уродства связанного со стандартной ХМЛ-сериализацией — конструкторы с параметрами нельзя, абстрактные классы нельзя и проч. и проч.
Re[2]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 16:44
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, Kore Sar, Вы писали:


ВВ>Ну первое что приходит в голову — а зачем что-то переименовывать? Нет, вы, конечно, можете изменить название самого свойства класса, но при этом просто не нужно менять название элемента в которое это свойство сериализуется.

Жизнь такая. Всё может быть. Перестраховуюсь.

ВВ>При измении типов определяйте для новых типов конверсию, т.е. чтобы MyOldType можно было бы привести к MyNewType.

Тут не понял. Какая именно конверсия?

ВВ>Но это в том случае, если использовать стандартную XML-сериализацию.


ВВ>Я бы в данном случае сделал сериализатор ручками. Причем сериализация бы происходила по манифесту, описанному в том же XML-формате. Манифест бы тупо маппил ХМЛ-элементы на классы, ХМЛ-атрибуты на св-ва и пр.

Т.е. рефлексия + парсинг ХМЛ-ки + парсинг манифеста ХМЛ-ного. Можно подумать. Спасибо за идею.

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


ВВ>Плюс не было бы всего этого уродства связанного со стандартной ХМЛ-сериализацией — конструкторы с параметрами нельзя, абстрактные классы нельзя и проч. и проч.

Конструкторы — это мелочь.
Абстрактные можно. XmlTypeAttribute для этого есть.
Какое еще там уродство есть, кроме уже перечисленного?
Re: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 16:52
Оценка: 3 (1)
Просто задавайте имена XML-атрибутов с помощью атрибутов семейства XmlAttribute (XmlRootAttribute, XmlAttribute, XmlArrayAttribute и т.д.).
После можете перименовывать свойства и классы, все будет работать как нужно. По удаления или добавления свойства/типа — это не проблема — к примеру при добавлении нового свойства сериалайзер просто не проинициализирует его из старого конфига, на такой случай надо задавать default-значение свойства. В общем у меня тоже конфиг постепенно рос и менялся, за несколько лет проблем не было.
В принципе проблем не будет даже если вы немного измените тип данных, к примеру был int стал string — конфиг все равно прочитается без ошибок, просто из при чтении соответствующего атрибута число которое там хранилось уже будет читаться как строка. Если же было к примеру свойство public List<SpecialDay> SpecialDays { get; set; } а станет List<DateTime> SpecialDays { get; set; } то конечно будут проблемы. Лично я бы в таком случае создал бы новое свойство в классе SettingsContainer, а в сеттере старого свойства сделал бы конвертацию и записывал бы данные уже в новое. При сохранении конфига можно рефлекшеном проставить атрибут XmlIgnore на такое deprecated свойство.
Re[2]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:03
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Просто задавайте имена XML-атрибутов с помощью атрибутов семейства XmlAttribute (XmlRootAttribute, XmlAttribute, XmlArrayAttribute и т.д.).

MC>После можете перименовывать свойства и классы, все будет работать как нужно. По удаления или добавления свойства/типа — это не проблема — к примеру при добавлении нового свойства сериалайзер просто не проинициализирует его из старого конфига, на такой случай надо задавать default-значение свойства. В общем у меня тоже конфиг постепенно рос и менялся, за несколько лет проблем не было.
MC>В принципе проблем не будет даже если вы немного измените тип данных, к примеру был int стал string — конфиг все равно прочитается без ошибок, просто из при чтении соответствующего атрибута число которое там хранилось уже будет читаться как строка. Если же было к примеру свойство public List<SpecialDay> SpecialDays { get; set; } а станет List<DateTime> SpecialDays { get; set; } то конечно будут проблемы. Лично я бы в таком случае создал бы новое свойство в классе SettingsContainer, а в сеттере старого свойства сделал бы конвертацию и записывал бы данные уже в новое. При сохранении конфига можно рефлекшеном проставить атрибут XmlIgnore на такое deprecated свойство.

Очень полезно. Спасибо.
Re[3]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 17:14
Оценка:
Здравствуйте, Kore Sar, Вы писали:

ВВ>>При измении типов определяйте для новых типов конверсию, т.е. чтобы MyOldType можно было бы привести к MyNewType.

KS>Тут не понял. Какая именно конверсия?

В смысле если тип меняется и становится не совместимым можно попробовать или описать для него преобразования через IConvertible или же вообще сделать враппер который будет отвечать за сериализацию.
Если к примеру вы Boolean поменяли на Enum — тут без враппера реализующего IXmlSerializable ИМХО не обойтись.

ВВ>>Но это в том случае, если использовать стандартную XML-сериализацию.


ВВ>>Я бы в данном случае сделал сериализатор ручками. Причем сериализация бы происходила по манифесту, описанному в том же XML-формате. Манифест бы тупо маппил ХМЛ-элементы на классы, ХМЛ-атрибуты на св-ва и пр.

KS>Т.е. рефлексия + парсинг ХМЛ-ки + парсинг манифеста ХМЛ-ного. Можно подумать. Спасибо за идею.

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


ВВ>>Плюс не было бы всего этого уродства связанного со стандартной ХМЛ-сериализацией — конструкторы с параметрами нельзя, абстрактные классы нельзя и проч. и проч.

KS>Конструкторы — это мелочь.

Ну если так судить, то все мелочь. Только в результате объектная модель в какой-то месс превращается.
И потом, а вдруг — если вы так уж любите перестраховываться — "завтра" вам потребуется один и тот же класс сериализовать в разный ХМЛ?

KS>Абстрактные можно. XmlTypeAttribute для этого есть.


Эээ, а как он поможет? Примерчик можно?

KS>Какое еще там уродство есть, кроме уже перечисленного?


Ну вот здесь к примеру обсуждается:
http://stackoverflow.com/questions/109318/using-net-what-limitations-if-any-are-there-in-using-the-xmlserializer/109354
Особенно характерен ответ с оценкой 8.
Сам я уже не очень помню, ибо давно не использовал это УГ.
Re[4]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:24
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, Kore Sar, Вы писали:


ВВ>>>При измении типов определяйте для новых типов конверсию, т.е. чтобы MyOldType можно было бы привести к MyNewType.

KS>>Тут не понял. Какая именно конверсия?

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

ВВ>Если к примеру вы Boolean поменяли на Enum — тут без враппера реализующего IXmlSerializable ИМХО не обойтись.

Тут рядом посоветовали просто сделать новый проперти и у старого переопределить сеттер, поставив старого в XmlIgnore.
Про IXmlSerializable не понял.



ВВ>Ну если так судить, то все мелочь. Только в результате объектная модель в какой-то месс превращается.

ВВ>И потом, а вдруг — если вы так уж любите перестраховываться — "завтра" вам потребуется один и тот же класс сериализовать в разный ХМЛ?

KS>>Абстрактные можно. XmlTypeAttribute для этого есть.


ВВ>Эээ, а как он поможет? Примерчик можно?


Можно, только я ошибся. Не XmlType, а XmlInclude.

[XmlInclude(typeof(Derived))]
abstract class Base
{
}
class Derived : Base
{
}


List<Base> collection легко и без проблем сериализуется.


KS>>Какое еще там уродство есть, кроме уже перечисленного?


ВВ>Ну вот здесь к примеру обсуждается:

ВВ>http://stackoverflow.com/questions/109318/using-net-what-limitations-if-any-are-there-in-using-the-xmlserializer/109354
ВВ>Особенно характерен ответ с оценкой 8.

Спасибо.

ВВ>Сам я уже не очень помню, ибо давно не использовал это УГ.
Re[5]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 17:31
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>Тут рядом посоветовали просто сделать новый проперти и у старого переопределить сеттер, поставив старого в XmlIgnore.


Я ошибся, забыл что атрибуты нельзя в runtime добавлять. А если XmlIgnore проставить, от он и читаться не будет, так что в этом случае надо что-то другое думать.
Re[6]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:37
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, Kore Sar, Вы писали:


KS>>Тут рядом посоветовали просто сделать новый проперти и у старого переопределить сеттер, поставив старого в XmlIgnore.


MC>Я ошибся, забыл что атрибуты нельзя в runtime добавлять. А если XmlIgnore проставить, от он и читаться не будет, так что в этом случае надо что-то другое думать.


Т.е. у тебя за всё время использования тип пропертей никогда не менялся?
Re[4]: Xml сериализация и сохранение совместимости
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.06.09 17:38
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Ну если так судить, то все мелочь. Только в результате объектная модель в какой-то месс превращается.

Никогда не считал классы для Xml сериализации частью объектной модели. Я их воспринимаю как суррогаты для сериализации, не больше. И собственно такой подход позволяет держать один текущий класс рабочий (пусть это будут таки настройки) и толпу XmlSettingsContainerV1, ... XmlSettingsContainerVN, специфичных для разных версий. Каждый из них умеет маппировать версию X в текущий класс настроек. Потому никаких ограничений на изменения между версиями нет. Одна проблема — перед десериализацией узнать, что именно десериализовывать. Но и она решается.

ВВ>И потом, а вдруг — если вы так уж любите перестраховываться — "завтра" вам потребуется один и тот же класс сериализовать в разный ХМЛ?

да, вот так рабочий SettingsContainer можно сериализовать в любой из XmlSettingsContainerVX и обратно. Код преобразования между рабочим классом и суррогатами рукописный.
Re[4]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:38
Оценка:
ВВ>Ну вот здесь к примеру обсуждается:
ВВ>http://stackoverflow.com/questions/109318/using-net-what-limitations-if-any-are-there-in-using-the-xmlserializer/109354
ВВ>Особенно характерен ответ с оценкой 8.

По этой же ссылке текст:

I (stupidly) wrote my own serializer to get around some of these problems. Don't do that; it is a lot of work and you will find subtle bugs in it months down the road.


Т.е. вариант предложеный тобой не подходит (времени у меня мало).
Re[5]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 17:41
Оценка: +1
Здравствуйте, Kore Sar, Вы писали:

KS>Т.е. вариант предложеный тобой не подходит (времени у меня мало).


Ну смотри сам, я всегда сериализацию делал "врукопашную" и проблем с ней не имел.
Re[5]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 17:43
Оценка:
Здравствуйте, samius, Вы писали:

ВВ>>И потом, а вдруг — если вы так уж любите перестраховываться — "завтра" вам потребуется один и тот же класс сериализовать в разный ХМЛ?

S>да, вот так рабочий SettingsContainer можно сериализовать в любой из XmlSettingsContainerVX и обратно. Код преобразования между рабочим классом и суррогатами рукописный.

Ну и чем это хорошо? Все заканчивается тем, что вы дублицируете объектную модель, фактически у вас получается сериализация Object Model -> Object Model for XML Serialization -> XML. Не проще ли сразу получать XML только более прямым способом? А то это все похоже на какие-то заплатки при работе с не самой лучшей библиотекой.
Re[4]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 17:44
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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

А чем поможет IConvertible?

ВВ>Если к примеру вы Boolean поменяли на Enum — тут без враппера реализующего IXmlSerializable ИМХО не обойтись.

Да, возможно в такой ситуации придется использовать wrapper. Хотя на самом деле я думаю что это все не пригодится.
Re[7]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 17:45
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>Т.е. у тебя за всё время использования тип пропертей никогда не менялся?


Нет. Они только добавлялись, удалялись и переименовывались.
Re[5]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 17:46
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>Тут рядом посоветовали просто сделать новый проперти и у старого переопределить сеттер, поставив старого в XmlIgnore.

KS>Про IXmlSerializable не понял.

Я имел в виду написать тип обвертку, который сам будет распарсивать старое значение и преобразовывать его в новое. У этого типа определить для удобства оператор привидения к "новому" типу — т.е. парсили булевый, получили энумерацию.

Кстати, вот такой вопрос — а когда приложение читает старый конфиг, оно должно уметь его сохранять в старом же формате или может сохранить уже в новом? ИМХО очень существенный момент.
Re[5]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:47
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Ну если так судить, то все мелочь. Только в результате объектная модель в какой-то месс превращается.

S>Никогда не считал классы для Xml сериализации частью объектной модели. Я их воспринимаю как суррогаты для сериализации, не больше. И собственно такой подход позволяет держать один текущий класс рабочий (пусть это будут таки настройки) и толпу XmlSettingsContainerV1, ... XmlSettingsContainerVN, специфичных для разных версий. Каждый из них умеет маппировать версию X в текущий класс настроек. Потому никаких ограничений на изменения между версиями нет. Одна проблема — перед десериализацией узнать, что именно десериализовывать. Но и она решается.

ВВ>>И потом, а вдруг — если вы так уж любите перестраховываться — "завтра" вам потребуется один и тот же класс сериализовать в разный ХМЛ?

S>да, вот так рабочий SettingsContainer можно сериализовать в любой из XmlSettingsContainerVX и обратно. Код преобразования между рабочим классом и суррогатами рукописный.


Ох как много кода вы предлагаете писать... Куча классов, для каждого преобразование, ... что-то мне такой подход не нравится.
Re[5]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 17:47
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Ну если так судить, то все мелочь. Только в результате объектная модель в какой-то месс превращается.

S>Никогда не считал классы для Xml сериализации частью объектной модели. Я их воспринимаю как суррогаты для сериализации, не больше. И собственно такой подход позволяет держать один текущий класс рабочий (пусть это будут таки настройки) и толпу XmlSettingsContainerV1, ... XmlSettingsContainerVN, специфичных для разных версий. Каждый из них умеет маппировать версию X в текущий класс настроек. Потому никаких ограничений на изменения между версиями нет. Одна проблема — перед десериализацией узнать, что именно десериализовывать. Но и она решается.

ВВ>>И потом, а вдруг — если вы так уж любите перестраховываться — "завтра" вам потребуется один и тот же класс сериализовать в разный ХМЛ?

S>да, вот так рабочий SettingsContainer можно сериализовать в любой из XmlSettingsContainerVX и обратно. Код преобразования между рабочим классом и суррогатами рукописный.

Угу, как вариант. На самом деле редко придется разные контейнеры разных версий и код преобразования делать. Если вообще когда либо придется. Как я уже написал если свойства просто добавляются/удаляются/переименовываются то все будет работать вообще без каких либо изменений.
Re[6]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 17:49
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>Ох как много кода вы предлагаете писать... Куча классов, для каждого преобразование, ... что-то мне такой подход не нравится.


Скорее всего все время будет только 1 класс. Просто в случае ОЧЕНЬ БОЛЬШИХ изменений придется написать контейнер для новой версии и код конвертации.
Re[6]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:50
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Здравствуйте, Kore Sar, Вы писали:


KS>>Т.е. вариант предложеный тобой не подходит (времени у меня мало).


ВВ>Ну смотри сам, я всегда сериализацию делал "врукопашную" и проблем с ней не имел.


У меня "врукопашную" бинарная сериализация. Спасибо, я уже настрадался с ней.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.