ISerialized 和向后兼容性

发布于 2024-08-28 13:07:57 字数 550 浏览 11 评论 0原文

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

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

和序列化代码。

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

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

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

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

我怎样才能做到这一点?

皮尔路易吉

I have to work an an old application that used binaryFormatter to serialize application data into filestream (say in a file named "data.oldformat")
without any optimizazion the main class has been marked with attribute

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

and the serialization code

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

In an attempt to optimize the serialization/deserialization process I simply made the class implement the ISerializable interface and wrote some optimized serialization routines

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

The optimization works really well but I MUST find a way to reatrive the data inside the old files for backward compatibility.

How can I do that??

Pierluigi

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鹤舞 2024-09-04 13:07:57

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 接口。

stmax has an excellent answer, however I would implement it like this, which uses SerializationEntry.GetEnumerator() instead of try/catch. This way is cleaner and significantly faster.

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

I would prefer a LINQ version using .FirstOrDefault(), but SerializationInfo does not implement IEnumerable - in face, weirdly enough, it doesn't even implement the old IEnumerable interface.

依 靠 2024-09-04 13:07:57

由于您已经实现了 ISerialized 接口,因此您可能也已经添加了所需的构造函数:

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

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

希望有帮助。

since you've already implemented the ISerializable interface, you've probably also already added the required constructor:

public MainClass(SerializationInfo info, StreamingContext context) {}

you can use the info-object passed to the constructor to retrieve data from the serialized file. by default (i.e. when no ISerializable is implemented), the fields names are used as identifiers during serialization. so if your old class had a field "int x" you can deserialize this using:

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

for newer versions i normally add a "version" entry during serialization, like this:

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

during deserialization you can check this version entry and deserialize accordingly:

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

i haven't compiled that code, might contain typos.

hope that helps.

关于从前 2024-09-04 13:07:57

只需尝试到目前为止您一直在做的同样的事情

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

实现 ISerialized 并没有改变您的原始类,基本上您只是添加了一些方法

Just try the same thing you've been doing so far

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

Implementing ISerializable didn't change your original class, basically you've just added some methods

墨小墨 2024-09-04 13:07:57

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

When serializing your objects add an additional Version field (this shouldn't add too much overhead). Then in your GetObjectData method, try to retrieve the version field first and based on whether this exists or not (by catching the SerializationException) deserialize the old way or the new way. The old way will have just serialized all data so you should just be able to call Get... for all fields.

烂人 2024-09-04 13:07:57

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

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

Your previous code should work. Do you get an exception?
Try to use new constructor:

 Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文