2011-11-23 80 views
4

我有一个应用程序使用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],但不会破坏与旧的序列化数据的兼容性?

我主要关心的是我不清楚反序列化是如何工作的。如果我加入类似于上面的处理另一个可选字段,它会起作用吗?我有什么其他选择可以更好地处理这些更改?

一如既往地提前致谢。

+0

使用binaryformatter按字段序列化字段感觉像有大量的开销大小。如果你想按字段序列化,你应该使用一个二进制打字机。我建议保留旧版本X版本的传统序列化方案,并将任何较新的版本传递给基于DataContracts和/或协议缓冲区的方案。 –

+0

确实; BinaryFormatter在版本化时可能会非常痛苦;基于合同的序列化器往往更友好(XmlSerializer,DataContractSerializer,protobuf-net等)。 –

回答

3

如果您用[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; 
     ... 
    } 
} 

但同样,必须强调 - 这是做事情的艰辛的道路:对 使用这种方法,你只处理实际存在的数据。

+0

感谢您的回答Marc(+1)。有一件事在我的问题中不太清楚,那就是该类本身目前没有[Serializable]。序列化的单个事物被标记为[可序列化](例如NewStuffIncludedRecently),但包含的类不是。如果我创建包含类[Serializable],我会向后兼容吗?这不会添加东西到对象图吗? – John

+0

@John如果它实现了ISerializable,那么其他属性基本上被忽略,完全取决于你反序列化它,检查是否存在。如果它既不是ISerializable也不是[Serializable],它不起作用,AFAIK。你可以枚举'info'来查看它包含的字段;让我知道你是否想要一个例子。 –

+0

@John我添加了一个SerializationEntry示例 –

相关问题