Как десериализовать старые данные для изменившегося типа?
-
12-09-2019 - |
Вопрос
У меня есть данные, которые были сохранены с использованием двоичной сериализации для следующего класса:
[Serializable]
public abstract class BaseBusinessObject
{
private NameValueCollection _fieldErrors = new NameValueCollection();
protected virtual NameValueCollection FieldErrors
{
get { return _fieldErrors; }
set { _fieldErrors = value; }
}
...
}
В какой-то момент класс был изменен на этот:
[Serializable]
public abstract class BaseBusinessObject
{
private Dictionary<string, string> _fieldErrors = new Dictionary<string, string>();
protected virtual Dictionary<string, string> FieldErrors
{
get { return _fieldErrors; }
set { _fieldErrors = value; }
}
...
}
Это вызывает проблемы с десериализацией старых данных.
Моей первой мыслью было реализовать ISerializable
, но у этого класса есть множество свойств, а также сотни наследующих классов, для которых мне также пришлось бы это реализовать.
Я хотел бы либо изменить старые данные, чтобы они соответствовали текущей структуре во время десериализации, либо иметь чистый способ обновления старых данных.
Решение
Добавьте новый _fieldErrors
под другим именем, скажем _fieldErrors2
, и сделай это [Optional]
.Затем реализуйте [OnDeserialized]
Метод, копирующий данные из _fieldErrors
к _fieldErrors2
(если присутствует) и очищает _fieldErrors.
Другие советы
Если данные используются только внутри, моей первой мыслью было бы написать какой-нибудь простой одноразовый код для десериализации ваших двоичных данных с использованием старой «NameValueCollection», сопоставить их со словарем и повторно сериализовать.Даже если обработка всех данных займет несколько дней, кажется, не стоит вносить исправления в новый код для поддержки старых данных.
Даже если он используется не только внутри страны, импортер кажется самым простым способом.
Добавляя к хорошему совету OlivierD, я бы посоветовал вам определить оба класса, но сначала попытаться десериализовать их как текущую версию.В блоке catch десериализуйте его как устаревшую версию, затем обновите ее до текущей и сохраните обратно.Если экземпляров устаревшей версии не существует, вы можете удалить код.
Рассмотрев несколько вариантов, я сделал следующие выводы:
В идеале я мог бы получить доступ к значению из оригинала NameValueCollection
и вручную преобразовать его в Dictionary<string, string>
.Единственный способ сделать это - реализовать ISerializable
, но это вызвало две основные проблемы:сопоставление имен устаревших данных и включение логики сериализации для всех наследующих классов (которых сотни).
По сути, это поставило меня в тупик.К счастью, мне удалось определить, что это поле на самом деле используется только как сводка ошибок проверки формы и вообще не должно сериализоваться, поэтому я исключил его из сериализации.