6

我必须使用一个旧应用程序,该应用程序使用 binaryFormatter 将应用程序数据序列化到文件流中(比如在名为“data.oldformat”的文件中),没有任何优化主类已用属性标记

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

和序列化代码

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

为了优化序列化/反序列化过程,我只是让类实现 ISerializable 接口并编写了一些优化的序列化例程

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

优化效果非常好,但我必须找到一种方法来重新获取旧文件中的数据以实现向后兼容性。

我怎样才能做到这一点??

皮尔路易吉

4

5 回答 5

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.");
    }
}

我还没有编译该代码,可能包含拼写错误。

希望有帮助。

于 2010-04-10T16:03:19.317 回答
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 接口。

于 2011-09-28T18:47:51.340 回答
0

试试你迄今为止一直在做的同样的事情

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

实现 ISerializable 并没有改变你原来的类,基本上你只是添加了一些方法

于 2010-04-10T15:54:59.860 回答
0

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

于 2010-04-10T15:58:32.873 回答
0

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

 Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
于 2010-04-10T16:00:02.097 回答