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>>Т.е. вариант предложеный тобой не подходит (времени у меня мало).


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


У меня "врукопашную" бинарная сериализация. Спасибо, я уже настрадался с ней.
Re[8]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:53
Оценка:
Здравствуйте, MozgC, Вы писали:

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


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


MC>Нет. Они только добавлялись, удалялись и переименовывались.


Это даёт мне надежду думать, что у нас будет тоже самое. (Упаси господи типы менять! Надо бы на стене повесить напоминалку — "Не менять типы пропертей в сеттингах!")
Re[6]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:54
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


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

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

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

Враппер вокруг чего? SettingsContainer-а или чего-то другого?


ВВ>Кстати, вот такой вопрос — а когда приложение читает старый конфиг, оно должно уметь его сохранять в старом же формате или может сохранить уже в новом? ИМХО очень существенный момент.

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

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


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

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

ВВ>Ну и чем это хорошо? Все заканчивается тем, что вы дублицируете объектную модель, фактически у вас получается сериализация Object Model -> Object Model for XML Serialization -> XML.

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

BB>Не проще ли сразу получать XML только более прямым способом?

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

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

KS>Враппер вокруг чего? SettingsContainer-а или чего-то другого?

Вокруг типа свойства в контейнере.
Re[7]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 17:58
Оценка:
Здравствуйте, MozgC, Вы писали:

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


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


MC>Скорее всего все время будет только 1 класс. Просто в случае ОЧЕНЬ БОЛЬШИХ изменений придется написать контейнер для новой версии и код конвертации.


Всё дело в том, что SettingsContainer передаётся по всему приложению (сотня мест). Вы предлагаете все сто мест менять на SettingsContainer2? Я заманаюсь!
Re[7]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 17:59
Оценка:
Здравствуйте, samius, Вы писали:

ВВ>>Ну и чем это хорошо? Все заканчивается тем, что вы дублицируете объектную модель, фактически у вас получается сериализация Object Model -> Object Model for XML Serialization -> XML.

S>Именно. Хорошо это тем, что позволяет забыть про код сериализации и не сковывать себя ограничениями при переходе с версии на версию. Плохо тем, что умножается код. Но это больше больше деклрация способа сериализации, чем код.
BB>>Не проще ли сразу получать XML только более прямым способом?
S>Иногда проще. А иногда проще держать толпу суррогатов.

Ну это вопрос уже философский, баталию не хочется устраивать
А вот представьте как было бы хорошо, если б в распоряжении был прямой XML-сериализатор, который позволял бы описывать контракт для сериализации в виде XML, и тогда бы эта ваша промежуточная модель заменилась бы на простой файлик с манифестом
Re[6]: Xml сериализация и сохранение совместимости
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.06.09 18:03
Оценка:
Здравствуйте, Kore Sar, Вы писали:

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


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



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


Не совсем. В каждый конкретный момент пишется только один класс. Пишется он методом копипаста а потом меняется под текущие нужды.
Много кода или нет, зато полный контроль в версиях. Да и кодом я это назвать могу с натяжкой. Схема xml, выполненная в классах. Код нужен только для преобразования. Его-то можно и наследовать хотя бы частично.
Re[8]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 18:04
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>Всё дело в том, что SettingsContainer передаётся по всему приложению (сотня мест). Вы предлагаете все сто мест менять на SettingsContainer2? Я заманаюсь!


Вы невнимателньо прочитали. Есть 1 класс с текущими настройками и классы специфичные для конкретной версии, которые умеют конвертировать настройки конкретной версии в текущую.
А вообще я ничего не предлагаю, это не я писал я просто вам объясняю что samius имел в виду
Re[8]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 18:05
Оценка:
Здравствуйте, MozgC, Вы писали:

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


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

KS>>Враппер вокруг чего? SettingsContainer-а или чего-то другого?

MC>Вокруг типа свойства в контейнере.


Т.е. предполжоим, что был у меня был bool MyChoice, и тип потом поменялся на enum ThreePosionBool.
Как должен должен будет выглядеть враппер?
Re[8]: Xml сериализация и сохранение совместимости
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.06.09 18:06
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

BB>>>Не проще ли сразу получать XML только более прямым способом?

S>>Иногда проще. А иногда проще держать толпу суррогатов.

ВВ>Ну это вопрос уже философский, баталию не хочется устраивать

не, не будем. Я не навязываю, только предложил свой вариант. ))

ВВ>А вот представьте как было бы хорошо, если б в распоряжении был прямой XML-сериализатор, который позволял бы описывать контракт для сериализации в виде XML, и тогда бы эта ваша промежуточная модель заменилась бы на простой файлик с манифестом

Я эту промежуточную модель так и воспринимаю, как файлик с манифестом. Только вот код преобразования ручной таки получается. А вообще было бы хорошо
Re[7]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 18:08
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>У меня "врукопашную" бинарная сериализация. Спасибо, я уже настрадался с ней.


Ты понимаешь, сериализатор — это такая штука, которая хорошо поддается автоматизированному тестированию. Если там чувак спустя месяцы в своем сериализаторе баги находил, то его проблемы, может он просто тестировать не умеет.
Re[9]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 18:09
Оценка:
Здравствуйте, MozgC, Вы писали:

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


KS>>Всё дело в том, что SettingsContainer передаётся по всему приложению (сотня мест). Вы предлагаете все сто мест менять на SettingsContainer2? Я заманаюсь!


MC>Вы невнимателньо прочитали. Есть 1 класс с текущими настройками и классы специфичные для конкретной версии, которые умеют конвертировать настройки конкретной версии в текущую.


Тьфу. Я идиот.


MC>А вообще я ничего не предлагаю, это не я писал я просто вам объясняю что samius имел в виду


Ну, что ж, остановлюсь пока на этом варианте. Спасибо.
Re[9]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 18:11
Оценка: 1 (1) +1
Здравствуйте, Kore Sar, Вы писали:

MC>>Вокруг типа свойства в контейнере.

KS>Т.е. предполжоим, что был у меня был bool MyChoice, и тип потом поменялся на enum ThreePosionBool.
KS>Как должен должен будет выглядеть враппер?

Ну описываешь класс ThreePositionBoolWrapper, реализуешь интерфейс IXmlSerializable.
В методе void ReadXml(XmlReader reader) проверяешь, что если текущее значение ридера "true"|"false", парсишь это как булевый, а если нет — то как значение энумерации.
Далее определяешь методы/операторы для привидения ThreePositionBoolWrapper к типу ThreePosionBool.
Как-то так.
Re: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 18:12
Оценка:
А у кого есть опыт работы с этой штукой NetDataContractSerializer?
Действительно она такая клёвая, как пишут здесь?
Re[10]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 25.06.09 18:21
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>Ну, что ж, остановлюсь пока на этом варианте. Спасибо.


Лично я бы все-таки не заморачивался. На крайняк можно будет сделать враппер как написал Воронков Василий и еще можно на всякий случай сохранять версию конфига, чтобы если что можно было бы приделать конвертер из старой версии в новую, но не делать его до тех пор пока он не понадобится (как я уже сказал очень вероятно что он не понадобится).
Re[11]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 18:32
Оценка:
Здравствуйте, MozgC, Вы писали:

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


KS>>Ну, что ж, остановлюсь пока на этом варианте. Спасибо.


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


Версия конфига планируется сохранятся.
Про врапперы понял.
Re[10]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 18:35
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

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


MC>>>Вокруг типа свойства в контейнере.

KS>>Т.е. предполжоим, что был у меня был bool MyChoice, и тип потом поменялся на enum ThreePosionBool.
KS>>Как должен должен будет выглядеть враппер?

ВВ>Ну описываешь класс ThreePositionBoolWrapper, реализуешь интерфейс IXmlSerializable.

ВВ>В методе void ReadXml(XmlReader reader) проверяешь, что если текущее значение ридера "true"|"false", парсишь это как булевый, а если нет — то как значение энумерации.
ВВ>Далее определяешь методы/операторы для привидения ThreePositionBoolWrapper к типу ThreePosionBool.
ВВ>Как-то так.

Понял. Уже писал такое.
Re[6]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 25.06.09 18:40
Оценка: :)
Здравствуйте, MozgC, Вы писали:

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


Ну вообще теоретически же можно атрибут в рантайме поставить — правда довольно джедайским способом — придется эмитить класс, клонирующий по стр-ре сериализуемый, заполнить его, и к нужному св-ву прибить XmlIgnore. Правда, по сравнению со всеми этими пассами собственный сериализатор кажется детской забавой
Re: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 25.06.09 19:15
Оценка:
Еще, вероятно, проблему с изменением сериализуемого типа можно решить подписавшить на эти ивенты у класса XmlSerializer:

UnknownAttribute Occurs when the XmlSerializer encounters an XML attribute of unknown type during deserialization.
UnknownElement Occurs when the XmlSerializer encounters an XML element of unknown type during deserialization.
UnknownNode Occurs when the XmlSerializer encounters an XML node of unknown type during deserialization.
UnreferencedObject Occurs during deserialization of a SOAP-encoded XML stream, when the XmlSerializer encounters a recognized type that is not used or is unreferenced.


Т.е. если попадётся старый тип bool, который надо привести к ThreeStatesBool, то подписавшись на UnreferencedObject можно будет сделать приведение в обработчике.
Например как тут.

Я прав?
Re[2]: Xml сериализация и сохранение совместимости
От: Воронков Василий Россия  
Дата: 26.06.09 08:25
Оценка:
Здравствуйте, Kore Sar, Вы писали:

KS>Я прав?


Это вообще совсем не то:

The UnreferencedObject event only occurs when the XmlSerializer is used to deserialize an XML document that contains a SOAP message that conforms to section 5 of the World Wide Web Consortium (www.w3.org) document, "Simple Object Access Protocol (SOAP) 1.1".

Documents that conform to section 5 are in a special format. At the very least, such a document includes the main body of the SOAP message. However, rather than having all types defined inline in the document, some type definitions can be encoded as references to top-level elements in the document. Thus, for every element found in the main body that is a reference, there must be a corresponding element that contains the type definition. To correlate the referencing element and the type definition, the type definition has an id attribute set to a unique string ID and the referencing element has an href attribute that references the same ID.


И событие генерируются, когда нет тайп-дефинишина.
Re[2]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 27.06.09 12:56
Оценка: 3 (1)
В общем вот я тут накидал все-таки вариант без заморочек.
Допустим сначала был такой класс конфига:

    [XmlRoot("config", IsNullable = false)]
    public class Config
    {
        private static readonly object _lockFlag = new object();
        private static Config _instance;
        private const string _configFilePath = "settings.xml";

        [XmlAttribute("ImportandData")]
        public string ImportandData { get; set; }

        [XmlArrayAttribute("DatesInfo")]
        public DateTime[] DatesInfo { get; set; }

        [XmlIgnore]
        public static Config Instance
        {
            get
            {
                lock (_lockFlag)
                {
                    if (_instance == null)
                    {
                        _instance = Load();
                    }
                }
                return _instance;
            }
        }

        private Config() { }

        public void Save()
        {
            var xmlSerializer = new XmlSerializer(typeof(Config));
            using (var writer = new StreamWriter(_configFilePath, false, System.Text.Encoding.GetEncoding("Windows-1251")))
            {
                xmlSerializer.Serialize(writer, this);
            }
        }

        private static Config Load()
        {
            if(!File.Exists(_configFilePath)) return new Config();

            var xmlSerializer = new XmlSerializer(typeof (Config));
            using (var xmlTextReader = new XmlTextReader(_configFilePath))
            {
                Config config = (Config) xmlSerializer.Deserialize(xmlTextReader);
                return config;
            }
        }

    }


Теперь вместо свойства public DateTime[] DatesInfo мы хотим сделать свойство public Date[] Dates. Для этого переделываем конфиг таким образом:

    [XmlRoot("config", IsNullable = false)]
    public class Config
    {
        private static readonly object _lockFlag = new object();
        private static Config _instance;
        private const string _configFilePath = "settings.xml";

        [XmlAttribute("ImportandData")]
        public string ImportandData { get; set; }

        ///<summary>This property is obsolete and is only used internally to support old config versions.</summary>
        [XmlArrayAttribute("DatesInfo")]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public DateTime[] DatesInfo
        {
            get
            { 
                throw new InvalidOperationException(
                    "This property is obsolete and is only used internally to support old config versions." );
            }
            set
            {
                var dates = from dt in value select new Date { Year = dt.Year, Month = dt.Month, Day = dt.Day };
                Dates = dates.ToArray();
            }
        }

        [XmlArrayAttribute("Dates")]
        public Date[] Dates { get; set; }

        [XmlIgnore]
        public static Config Instance
        {
            get
            {
                lock (_lockFlag)
                {
                    if (_instance == null)
                    {
                        _instance = Load();
                    }
                }
                return _instance;
            }
        }

        private Config() { }

        public void Save()
        {
            var attrs = new XmlAttributes { XmlIgnore = true };
            var attrOverrides = new XmlAttributeOverrides();
            attrOverrides.Add(typeof(Config), "DatesInfo", attrs);

            var xmlSerializer = new XmlSerializer(typeof(Config), attrOverrides);
            using (var writer = new StreamWriter(_configFilePath, false, System.Text.Encoding.GetEncoding("Windows-1251")))
            {
                xmlSerializer.Serialize(writer, this);
            }
        }

        private static Config Load()
        {
            if (!File.Exists(_configFilePath)) return new Config();

            var xmlSerializer = new XmlSerializer(typeof(Config));
            using (var xmlTextReader = new XmlTextReader(_configFilePath))
            {
                Config config = (Config)xmlSerializer.Deserialize(xmlTextReader);
                return config;
            }
        }
    }

    // ...

    public class Date
    {
        public int Year { get; set; }
        public int Month { get; set; }
        public int Day { get; set; }
    }


Все, при чтении старой версии конфига сеттер устаревшего свойства сконвертирует данные в новый тип и присвоит их новому свойству. А при сохранении конфига добавляем атрибут XmlIgnore устаревшему свойству так, что оно больше не запишется в конфиг. В геттере устаревшего свойства вместо исключения можно производить обратную конверсию — это уже по желанию.

Плюсы:
+ нет заморочек

Минусы:
— В классе конфига остается устаревшее свойство. Атрибут Obsolete нельзя применить, т.к. в таком случае сериалайзер не будет его читать.
Re[3]: Xml сериализация и сохранение совместимости
От: Kore Sar  
Дата: 27.06.09 14:15
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Все, при чтении старой версии конфига сеттер устаревшего свойства сконвертирует данные в новый тип и присвоит их новому свойству. А при сохранении конфига добавляем атрибут XmlIgnore устаревшему свойству так, что оно больше не запишется в конфиг. В геттере устаревшего свойства вместо исключения можно производить обратную конверсию — это уже по желанию.


MC>Плюсы:

MC>+ нет заморочек

MC>Минусы:

MC>- В классе конфига остается устаревшее свойство. Атрибут Obsolete нельзя применить, т.к. в таком случае сериалайзер не будет его читать.

Клёво!
Пара впоросов.
1) Атрибут XmlIgnore устаревшему свойству Вы забыли поставить. Верно?
2) Что значит Osboslete нельзя применять, потому что сериалайзер не будет его читать? Что значит "читать" в данном случае?
3) Для чего EditorBrowsable(EditorBrowsableState.Never)?
Re[4]: Xml сериализация и сохранение совместимости
От: MozgC США http://nightcoder.livejournal.com
Дата: 27.06.09 15:47
Оценка: 6 (1)
Здравствуйте, Kore Sar, Вы писали:

KS>Клёво!

KS>Пара впоросов.
KS>1) Атрибут XmlIgnore устаревшему свойству Вы забыли поставить. Верно?
Нет, внимательно посмотрите код метода Save(). Атрибут XmlIgnore для устаревшего свойства указывается в рантайме с помощью класса XmlAttributeOverrides.

KS>2) Что значит Osboslete нельзя применять, потому что сериалайзер не будет его читать? Что значит "читать" в данном случае?

Это значит будет вести себя так как будто этого свойства нет, или как будто на нем атрибут XmlIgnore. Т.е. при чтении старого конфига на новой версии программы, устаревшее свойство не будет устанавливаться, т.е. не будет вызываться его сеттер, а следовательно не будет происходить требуемой конвертации. В результате новое свойство при чтении старого конфига останется null.

KS>3) Для чего EditorBrowsable(EditorBrowsableState.Never)?

При использовании класса в коде другой сборки, или к примеру при включении соответствующего фильтра в ReSharper'е (ReSharper -> Options -> Intellisense -> Completion Appearance -> Filter members by [EditorBrowsable] attribute), свойства помеченные таким атрибутом не будут показываться в Intellisense, т.е. это дополнительно снизит вероятность попытки использования устаревшего свойства программистом который "не в курсе" что оно устарело. С этой же целью еще и XmlDoc добавлен.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.