Десериализация необязательных полей из BinaryFormatter - PullRequest
4 голосов
/ 23 ноября 2011

У меня есть приложение, которое сериализует данные, используя 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 Ответ

3 голосов
/ 23 ноября 2011

Если вы пометите новые поля как [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При таком подходе вы обрабатываете только те данные, которые действительно есть.

...