Совместимость с последовательной последовательностью XML С# назад

Ранее методы сериализации/десериализации использовали тип Item:

public class Item{}

Теперь у меня есть новый класс под названием ItemWrapper, полученный из Item с дополнительным свойством:

public class ItemWrapper : Item
{
    public string NewProperty { get; set; }
}

Теперь мои методы сериализации/десериализации используют тип ItemWrapper. И теперь я нарушил совместимость. Я не могу загрузить файлы XML типа Item, которые были сохранены в более старых версиях. Я рассмотрел возможность установки try/catch по методу десериализации, когда он пытается десериализовать Item как ItemWrapper, а затем в catch я попытался бы десериализоваться как Item. Или я мог бы xPath увидеть структуру XML, и если no ItemWrapper найдено, я мог бы считать его Item. Оба этих решения выглядят взломанными, и я уверен, что есть лучший подход к решению этой ситуации. Любые идеи?

Ответ 1

Хороший вопрос. Во-первых, расширение класса путем деривации является хорошим следованием принципу Open/Closed, если все потребители Item теперь потребляют ItemWrapper, тогда вы не накопили много усилий для реализации производного класса. Если ItemWrapper теперь является единственной конкрецией в использовании, то слейте его новое свойство с Item и сделайте.

Если вам нужно сохранить оба конкреции, то ItemWrapper нужно украсить несколькими атрибутами, чтобы указать, как XMLSerializer должен преобразовываться в строки XML и из них. Информацию об атрибутах XML можно найти здесь.

В частности, я обращаю ваше внимание на XmlTypeAttribute. Это украшает класс ItemWrapper и сообщает XmlSerializer использовать конкретное пространство имен и имя типа вместо автоматического генерации их на основе имени класса. Вы можете использовать это, чтобы сделать ItemWrapper совместимым с XML файлами, созданными путем сериализации Item, указав, что класс ItemWrapper должен создавать и использовать сериализации XML, помеченные как <Item>. Тем не менее, элемент, если он все еще работает, не удастся при попытке десериализовать файл, созданный путем сериализации ItemWrapper, поэтому это решение не является передовым и поэтому предыдущие версии вашего программного обеспечения, если вы не справлялись с ошибками сериализации, будет умирать огненной смертью без видимых причин при предоставлении более новых файлов

По этой причине обычно рекомендуется реализовать какую-то схему управления версиями в вашей сериализации. Это может быть так же просто, как общедоступное свойство readonly для ваших типов, которое может быть помечено атрибутом XmlAttribute, сообщая XmlSerializer о создании тега <Item> как <Item xmlVersion="1.0.0">. Если бы вы это делали, то ItemWrapper мог бы переопределить это поле, чтобы вернуть "1.1.0", что позволяет XML файлам быть легко дифференцируемыми и поэтому позволяет вам проверять несовместимую версию файла с XmlTextReader и изящно возвращать ошибку если файл был сгенерирован более поздней версией программного обеспечения.