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