【问题标题】:implementing ISerializable for version control为版本控制实现 ISerializable
【发布时间】:2015-01-07 17:32:03
【问题描述】:

考虑以下 POD 类型的类:

public class Price { public decimal OfferPrice { get; set; } }

这个类的对象是从服务器获取的,所以让我们用 Serializable 来装饰它

[Serializable]
public class Price { public decimal OfferPrice { get; set; } }

现在有两个客户端在不同的机器上检索这些对象。他们不会发送价格。他们都得到了普莱斯程序集的副本。

现在这个类被 BonusPrice 扩展了。

[Serializable]
public class Price { 
  public decimal OfferPrice { get; set; } 
  public decimal BonusPrice { get; set; } 
}

新程序集部署到服务器,部署到其中一个客户端,而不是另一个。 所以旧版本的客户端在(反)序列化 Price 对象时会崩溃。

旧版本的客户端不需要 BonusPrice 字段,因此在版本不同时它可以继续工作会很好。 因此,我正在考虑从一开始就实现 ISerializable,因此第一个和第二个版本看起来像:

// version 1.0
[Serializable]
public class Price : ISerializable {
  protected Price(SerializationInfo info, StreamingContext context) {
    OfferPrice = info.GetDecimal("op");
  }

  [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
  public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
    info.AddValue("op", OfferPrice);
  }
}

// version 2.0
[Serializable]
public class Price : ISerializable {
  protected Price(SerializationInfo info, StreamingContext context) {
    OfferPrice = info.GetDecimal("op");
    BonusPrice = info.GetDecimal("bp");
  }

  [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
  public virtual void GetObjectData(SerializationInfo info, StreamingContext context) {
    info.AddValue("op", OfferPrice);
    info.AddValue("bp", BonusPrice);
  }
}

所以现在当一个客户端没有更新到版本 2 时,它仍然会继续仅反序列化 OfferPrice 而不会崩溃。当它在某个时候更新时,它会自动使用 BonusPrice。

我的问题:在只读取对象时,实现 ISerializable 是一种进行版本控制的好方法吗? 这些问题通常是如何解决的?

【问题讨论】:

  • 好问题,正如我在回答中提到的,您可以使用OptionalFieldAttribute 我从未使用过它,因为当我知道存在类似的东西时为时已晚。 FWIW 我使用ISerializable 仅用于控制我的项目中的版本控制。

标签: c# .net version-control versioning


【解决方案1】:

您可以使用OptionalFieldAttribute 来控制BinaryFormatterSoapFormatter 的版本控制。

OptionalFieldAttribute 具有 VersionAdded 属性。在 .NET Framework 2.0 版中,不使用此功能。但是,正确设置此属性以确保该类型与未来的序列化引擎兼容非常重要。

该属性指示给定字段的类型的版本 添加。它应该每增加一个(从 2 开始) 修改类型的时间

还有其他方法,如序列化回调、SerializationBinder、ISerializable 等。

更多信息请参考Version Tolerant Serialization

【讨论】:

  • 这当然更容易。那么如果 CLR 无法通过反射找到它们并且不抛出异常,则不会序列化这些字段?
  • @ServéLaurijssen 是的,当数据丢失时,序列化程序不会抛出异常(它只会忽略),反之亦然。
【解决方案2】:

在我看来,您正试图在一份合同中混合使用两种协议版本。在您的示例中,它可以工作,但实际上通常很难统一新协议,因此最好将它们分开。换句话说,您的服务器必须独立支持这两个版本。看看OData Protocol Versioning

【讨论】:

    猜你喜欢
    • 2011-03-24
    • 2011-06-28
    • 1970-01-01
    • 2018-04-22
    • 2018-01-21
    • 2013-10-21
    • 2010-11-20
    • 2010-09-20
    • 2022-01-02
    相关资源
    最近更新 更多