【问题标题】:ISerializable and backward compatibilityISerializable 和向后兼容性
【发布时间】:2011-02-06 12:26:05
【问题描述】:

我必须使用一个旧应用程序,该应用程序使用 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

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

我该怎么做??

皮尔路易吉

【问题讨论】:

    标签: .net backwards-compatibility binaryformatter iserializable


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      由于您已经实现了 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.");
          }
      }
      

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

      希望有帮助。

      【讨论】:

      • 很好的答案 stmax!你是如何找到 binaryformatter 对象的默认行为的?
      • 我执行以下操作来查找使用默认行为序列化的条目的“名称”: foreach (SerializationEntry entry in info.GetEnumerator()) { Trace.WriteLine(entry.Name); }
      • 获取“版本”时不要尝试/捕获,而是使用 SerializationInfo.GetEnumerator() 并搜索“版本”字段。它更干净,如果找不到该字段,那么避免抛出异常会使整个反序列化(在我的测试中)快 2 倍。 SerializationInfo.Get() 在内部使用与自己使用枚举器进行相同的线性搜索,使它们在字段数上都是 O(n)。
      • +1 保持向后兼容性的好方法。但是,虽然您是正确的,可以通过使用实际的字段名称来访问字段值,但这不适用于自动属性。然后编译器使用格式“k__BackingField”。我会将此信息添加到您的答案中,如果您愿意,可以接受。
      【解决方案3】:

      试试你目前为止一直在做的事情

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

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

      【讨论】:

      • 我已经添加了所需的构造函数(serializationInfo 信息、streamingContext 上下文),所以我不能使用 b.deserialize 而不知道主类在默认序列化期间如何保存自己的数据
      【解决方案4】:

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

      【讨论】:

      • 这对于使用 getObjectData 的序列化过程很好,但问题是在反序列化过程中使用专门的构造函数 new(info as serializationinfo,context as serializationcontext) 旧的 mainClass 版本没有实现 ISerializable所以我不知道如何使用 streaminginfo 对象检索数据
      【解决方案5】:

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

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

      【讨论】:

      • 我有..但是当类只标记为可序列化时,它需要知道二进制格式化程序如何保存数据......
      猜你喜欢
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2012-12-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多