Как десериализовать старые данные для типа, который изменился? - PullRequest
9 голосов
/ 11 августа 2009

У меня есть данные, которые были сохранены с использованием двоичной сериализации для следующего класса:

[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, но этот класс обладает многочисленными свойствами, а также сотнями классов наследования, для которых мне также пришлось бы реализовать это.

Я бы хотел либо изменить старые данные, чтобы они соответствовали текущей структуре во время десериализации, либо иметь чистый способ обновления старых данных.

Ответы [ 4 ]

4 голосов
/ 11 августа 2009

Добавьте новый _ fieldErrors под другим именем, скажем _fieldErrors2, и сделайте его [Optional]. Затем реализуйте метод [OnDeserialized], который копирует данные из _fieldErrors в _fieldErrors2 (если имеется) и очищает _fieldErrors.

3 голосов
/ 11 августа 2009

Если данные используются только для внутренних целей, моей первой мыслью было бы написать какой-нибудь простой одноразовый код для десериализации ваших двоичных данных с использованием старого «NameValueCollection», сопоставления его со словарем и повторной сериализации. Даже если на обработку всех данных уйдет несколько дней, вряд ли стоит внедрять патч для вашего нового кода для поддержки старых данных.

Даже если он используется не только внутри страны, импортер кажется самым простым способом.

2 голосов
/ 11 августа 2009

В дополнение к хорошему совету OlivierD, я бы посоветовал вам определить оба класса, но сначала попытайтесь десериализовать как текущую версию. В вашем блоке catch десериализуйте его как унаследованную версию, затем обновите до текущей и сохраните обратно. Если экземпляров устаревшей версии не существует, вы можете удалить код.

0 голосов
/ 12 августа 2009

Изучив несколько вариантов, я сделал следующие выводы:

В идеале я бы смог получить доступ к значению из исходного NameValueCollection и вручную преобразовать его в Dictionary<string, string>. Единственный способ сделать это - реализовать ISerializable, но это породило две основные проблемы: сопоставление именования устаревших данных и включение логики сериализации для всех наследуемых классов (которых насчитывается сотни).

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

...