【问题标题】:Strategy for deserializing a class that has changed in .NET反序列化 .NET 中已更改的类的策略
【发布时间】:2012-04-19 22:42:23
【问题描述】:

我有这门课

[Serializable]
public class myClass() : ISerializable
{
    public int a;
    public int b;
    public int c;

    public void GetObjectData(SerializationInfo info, 
                              StreamingContext context)
        {
        // Some code
        }

    public myClass(SerializationInfo info, 
                   StreamingContext context)
        {
        // Some code
        }
}

我的数据库中有数百个这样的对象。我现在准备发布我的应用程序的新版本,其中的类已演变为

[Serializable]
public class myClass() : ISerializable
{
    public int a;
    public string b;
    public int c;
    public bool d;

    public void GetObjectData(SerializationInfo info, 
                              StreamingContext context)
        {
        // Some code
        }

    public myClass(SerializationInfo info, 
                   StreamingContext context)
        {
        // Some code
        }
}

如何使用第二个版本的反序列化构造函数反序列化基于第一个版本序列化的对象。

是否还有未来版本校对我的第二版课程的策略?

【问题讨论】:

  • 制作一个转换器程序,读取第一种类型的对象,生成第二种类型的对象,并用新的替换旧的。如果您谈论的是数百条而不是数百万条记录,那么运行该程序应该需要很长时间。
  • 有一篇关于它的专用 MSDN 文章。最好从那里开始:msdn.microsoft.com/en-US/library/ms229752%28v=vs.90%29.aspx

标签: c# .net serialization


【解决方案1】:

如果您没有准备,您可能需要求助于 hack:当您的 public myClass 反序列化构造函数获取 bool d 的值时,将代码包含在 try/catch 中,并设置 d捕获异常时恢复到默认值。

将来,添加一个 int"__ver"(或任何其他不与您传递给 info.AddValue 的参数冲突的名称),并将其设置为您在类中维护的常量以指示序列化的兼容和不兼容变化:

public class myClass : ISerializable {
    private const int __ver = 4;
    public int a;
    public string b;
    public int c;
    public bool d;

    public void GetObjectData(SerializationInfo info, 
                          StreamingContext context) {
        info.AddValue("__ver", ver);
        info.AddValue("a", a);
        // and so on
    }

    public myClass(SerializationInfo info, 
               StreamingContext context) {
        switch(info.GetInt32("__ver")) {
            case 3: 
                // Deserialize prior version
            break;
            case 4: 
                // Deserialize current version
            break;
        }
    }
}

【讨论】:

  • 唯一的问题是数据库中的所有当前实例都没有 __ver 字段,因此您将无法改进此实现。
  • SerializationInfo 没有类似ContainsKey() 的东西吗?我认为这在这里会非常有用。
  • 我认为您可以使用MemberCountGetEnumerator() 来避免try/catch
  • @PeteDavis 正确 - 这是我回答第一段的主题。
【解决方案2】:

Serializable 类非常适合通过相同版本的软件传递它们,但是在使用它进行持久性时您很快就会遇到这个问题。如果您要将对象存储为BLOBs,那么可以使用protobuf-net 之类的东西,它允许通过允许可选字段来进行序列化版本控制。

考虑到你目前的困境,你可以做的就是让它立即工作,对新字段进行尝试,如果它们不存在则默认它们:

protected myClass(SerializationInfo info, StreamingContext context)
{
    c = info.GetInt32("Value_C"); 
    try
    {
        b = info.GetBoolean("Value_B");
    }
    catch (SerializationException)
    {
        b = true;
    }
}

【讨论】:

    猜你喜欢
    • 2011-05-20
    • 2011-12-06
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多