Десериализация необязательных полей из BinaryFormatter

У меня есть приложение, которое сериализует данные, используя BinaryFormatter, Член был добавлен в класс, который был сериализован от одной версии к другой без изменения имени класса. Код был добавлен для обработки возможного отсутствия добавленного члена в старых сериализованных файлах:

private void readData(FileStream fs, SymmetricAlgorithm dataKey)
{
    CryptoStream cs = null;

    try
    {
        cs = new CryptoStream(fs, dataKey.CreateDecryptor(),
            CryptoStreamMode.Read);
        BinaryFormatter bf = new BinaryFormatter();

        string string1 = (string)bf.Deserialize(cs);
        // do stuff with string1

        bool bool1 = (bool)bf.Deserialize(cs);
        // do stuff with bool1

        ushort ushort1 = (ushort)bf.Deserialize(cs);
        // do stuff with ushort1

        // etc. etc. ...

        // this field was added later, so it may not be present
        // in the serialized binary data.  Check for it, and if
        // it's not there, do some default behavior

        NewStuffIncludedRecently newStuff = null;

        try
        {
            newStuff = (NewStuffIncludedRecently)bf.Deserialize(cs);
        }
        catch
        {
            newStuff = null;
        }

        _newStuff = newStuff != null ?
                new NewStuffIncludedRecently(newStuff) :
                new NewStuffIncludedRecently();
    }
    catch (Exception e)
    {
        // ...
    }
    finally
    {
        // ...
    }
}

Суть в том, что я сейчас нахожусь в том, что я действительно хотел бы просто промыть и повторить с другим участником, которого я хотел бы добавить, что означало бы, что я добавил бы другое поле и блок try-catch, подобный тому, что NewStuffIncludedRecently,

Я думал просто сделать весь класс [Serializable] но не нарушит ли это совместимость со старыми сериализованными данными?

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

Заранее спасибо как всегда.

1 ответ

Решение

Если вы пометите новые поля с [OptionalField] это должно сработать, но я слышал сообщения о слабости в некоторых случаях. Я не могу сказать наверняка, так как я избегаю BinaryFormatter, потому что у него так много проблем при управлении версиями:) (плюс, он не такой "жесткий", как некоторые альтернативы, и имеет серьезные проблемы, если вы хотите перейти на кроссплатформенность или CF/SL и т. д.)

Если вы реализуете ISerializableВы можете попробовать:

foreach(SerializationEntry entry in info) {
    switch(entry.Name) {
         case "Name": Name = (string)info.Value;
         case "Id": Id = (int)info.Value;
         ...
    }
}

Но опять же, должен подчеркнуть - это делает вещи трудным путем: p При таком подходе вы обрабатываете только те данные, которые действительно есть.

Другие вопросы по тегам