6

我要工作所用BinaryFormatter的应用程序数据序列化为FILESTREAM的旧应用程序 没有任何optimizazion(在一个名为“data.oldformat”文件说)主类已被打上属性ISerializable的和向后兼容性

<serializable()>public MainClass 
....... 
end class 

和序列化代码

dim b as new binaryformatter 
b.serialize(mystream,mymainclass) 

在试图优化序列化/反序列化过程简单地我提出的类实现ISerializable接口和写了一些优化seriali矩阵特殊积例程

<serializable()>public MainClass 
     implements ISerializable 
....... 
end class 

优化的作品真的很好,但我必须找到一个方法来reatrive旧文件中的数据的后向兼容性。

我该怎么做?

皮耶路易吉

回答

4

stmax具有优良的答案,不过,我想实现它这样的,它采用SerializationEntry.GetEnumerator()而不是try/catch。这种方式更干净,速度更快。

public MainClass(SerializationInfo info, StreamingContext context) { 
    int version = 0; 
    foreach (SerializationEntry s in info) 
    { 
     if (s.Name == "version") 
     { 
      version = (int)s.Value; 
      break; 
     } 
    } 

    switch (version) { 
     case 0: 
     // deserialize "old format" 
     break; 
     case 1: 
     // deserialize "new format, version 1" 
     break; 
     default: 
     throw new NotSupportedException("version " + version + " is not supported."); 
    } 
} 

我宁愿使用.FirstOrDefault()LINQ的版本,但SerializationInfo中不实现IEnumerable - 在脸上,古怪的是,它甚至没有实现旧IEnumerable接口。

0

刚刚尝试同样的事情,你到目前为止一直在做

BinaryFormatter b = new BinaryFormatter(); 
MainClass a = b.DeSerialize(mystream) as MainClass; 

实施了ISerializable并没有改变原来的类,基本上你刚刚增加了一些方法

+0

我已经添加了所需的构造函数(serializationInfo info,streamingContext上下文),所以我不能在不知道主类如何在默认序列化过程中保存自己的数据的情况下不能使用b.deserialize – pierusch 2010-04-10 16:11:16

0

序列化对象时添加一个额外的版本字段(这不应该增加太多开销)。然后在GetObjectData方法中,首先尝试检索版本字段,并根据是否存在版本字段(通过捕获SerializationException)反序列化旧方式或新方法。旧的方法将只是序列化所有的数据,所以你应该能够为所有字段调用Get ...。

+0

对于使用序列化过程getObjectData,但问题是在反序列化过程中使用专门的构造函数 新(信息作为serializationinfo,上下文作为序列化上下文) 旧的mainClass版本没有实现ISerializable所以我不知道如何使用streaminginfo检索数据object – pierusch 2010-04-10 16:06:22

0

你以前的代码应该可以工作。你有例外吗? 尝试使用新的构造:

Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext) 
+0

I had..but它需要知道binaryformatter如何在类仅标记为可序列化时保存数据... – pierusch 2010-04-10 16:12:13

4

,因为你已经实现ISerializable接口,你可能也已经添加了必需的构造函数:

public MainClass(SerializationInfo info, StreamingContext context) {} 

可以使用通过信息对象到构造函数从序列化文件中检索数据。默认情况下为(即,当不实现ISerializable时),字段名称在序列化期间用作标识符。所以如果你的老班有场“INT X”,你可以使用反序列化这样:

this.x = info.GetInt32("x"); 

的新版本,我通常序列化过程中添加一个“版本”项,这样的:

public void GetObjectData(SerializationInfo info, StreamingContext context) { 
    info.AddValue("version", 1); 
    info.AddValue("othervalues", ...); 
} 

反序列化过程中,您可以检查此版本的条目,并据此反序列化:

public MainClass(SerializationInfo info, StreamingContext context) { 
    int version; 
    try { 
     version = info.GetInt32("version"); 
    } 
    catch { 
     version = 0; 
    } 

    switch (version) { 
     case 0: 
     // deserialize "old format" 
     break; 
     case 1: 
     // deserialize "new format, version 1" 
     break; 
     default: 
     throw new NotSupportedException("version " + version + " is not supported."); 
    } 
} 

我还没有编译的代码,可能包含错别字。

希望有帮助。

+0

很好的答案stmax!你如何找到binaryformatter对象的默认行为? – pierusch 2010-04-10 16:15:04

+3

我做了以下操作来查找使用默认行为序列化的条目的“名称”:foreach(info.GetEnumerator()中的SerializationEntry条目){Trace.WriteLine(entry.Name); } – stmax 2010-04-10 18:05:25

+0

取代“try/catch”时获取“版本”,而是使用SerializationInfo.GetEnumerator()并搜索“版本”字段。它更干净,如果没有找到该字段,那么避免抛出异常会使整个反序列化(在我的测试中)速度提高2倍。 SerializationInfo.Get()在内部使用与使用枚举器自己做同样的线性搜索,使它们在字段数中都是O(n)。 – 2011-09-28 18:42:00