【问题标题】:Serialization and versioning序列化和版本控制
【发布时间】:2011-03-12 05:56:47
【问题描述】:

我需要将一些数据序列化为字符串。然后将该字符串存储在 DB 中的特殊列 SerializeData 中。

我创建了用于序列化的特殊类。

[Serializable]
public class SerializableContingentOrder
{
    public Guid SomeGuidData { get; set; }
    public decimal SomeDecimalData { get; set; }
    public MyEnumerationType1 EnumData1 { get; set; }
}

序列化:

protected override string Serialize()
{
    SerializableContingentOrder sco = new SerializableContingentOrder(this);

    MemoryStream ms = new MemoryStream();
    SoapFormatter sf = new SoapFormatter();
    sf.Serialize(ms, sco);
    string data = Convert.ToBase64String(ms.ToArray());
    ms.Close();
    return data;
}

反序列化:

protected override bool Deserialize(string data)
{
    MemoryStream ms = new MemoryStream(Convert.FromBase64String(data).ToArray());
    SoapFormatter sf = new SoapFormatter();

    SerializableContingentOrder sco = sf.Deserialize(ms) as SerializableContingentOrder;
    ms.Close();
    return true;
}

现在我想要版本控制支持。如果我更改 SerializableContingentOrder 课程会发生什么。我希望将来能够添加新字段。

我必须切换到 DataContract 序列化吗?请给我简短的sn-p?

【问题讨论】:

  • 见 MSDN; SoapFormatter 已正式过时:msdn.microsoft.com/en-us/library/…
  • 我需要问类似的问题,但有点扩展。数据肯定会发生变化,我们可以让数据结构自己处理下一次变化吗?

标签: c# .net serialization versioning


【解决方案1】:

如果您想支持版本控制,您有两种选择。使用 DataContracts 或使用 Version Tolerant Serialization。两者都有效。

DataContacts 自动处理字段的添加和删除。有关详细信息,请参阅 Data Contact Versioning 和 Best Practices: Data Contract Versioning。

DataContact 示例

[DataContract]
public class ContingentOrder
{
    [DataMember(Order=1)]
    public Guid TriggerDealAssetID;

    [DataMember(Order=2)]
    public decimal TriggerPrice;

    [DataMember(Order=3)]
    public TriggerPriceTypes TriggerPriceType;

    [DataMember(Order=4)]
    public PriceTriggeringConditions PriceTriggeringCondition;

}

版本容错序列化示例

// Version 1
[Serializable]
public class SerializableContingentOrder
{
    public Guid TriggerDealAssetID;
    public decimal TriggerPrice;
    public TriggerPriceTypes TriggerPriceType;
    // Omitted PriceTriggeringCondition as an example
}

// Version 2 
[Serializable]
public class SerializableContingentOrder
{
    public Guid TriggerDealAssetID;
    public decimal TriggerPrice;
    public TriggerPriceTypes TriggerPriceType;

    [OptionalField(VersionAdded = 2)]
    public PriceTriggeringConditions PriceTriggeringCondition;

    [OnDeserializing]
    void SetCountryRegionDefault (StreamingContext sc)
    {
        PriceTriggeringCondition = /* DEFAULT VALUE */;
    }

}

有关版本容忍序列化的更多信息(链接已损坏)。尤其要注意页面底部的最佳实践。

注意,DataContracts 是在 .NET 3.5 中引入的,因此如果您需要以 .NET 2.0 为目标,您可能没有该选项。

HTH,

【讨论】:

  • OptionalField 不适用于 'struct' 类型的数据成员,例如 'Guid'。 “当一个类有结构字段时,OptionalFieldAttribute 将停止工作。”在这里阅读:bytes.com/topic/net/answers/…
  • 谢谢@Nayan,我不知道。一种可能的解决方案/解决方法是使用 Nullable<T> 包装结构。
【解决方案2】:

我强烈主张反对在数据库中存储BinaryFormatter或SoapFormatter数据;它是:

  • 易碎
  • 不兼容版本
  • 不独立于平台

BinaryFormatter 可以用于 .NET 程序集之间的数据传输(在推送中),但我建议使用更可预测的序列化程序。 DataContractSerializer 是一个选项(与 JSON 或 XmlSerializer 一样),但出于上述所有相同原因,我不会使用 NetDataContractSerializer。我会很想使用 protobuf-net,因为它是一种已知高效格式的高效二进制文件,独立于平台且版本容错!

例如:

[DataContract]
public class SerializableContingentOrder
{
    [DataMember(Order=1)] public Guid SomeGuidData { get; set; }
    [DataMember(Order=2)] public decimal SomeDecimalData { get; set; }
    [DataMember(Order=3)] public MyEnumerationType1 EnumData1 { get; set; }
}

序列化:

protected override string Serialize()
{
    SerializableContingentOrder sco = new SerializableContingentOrder(this);   
    using(MemoryStream ms = new MemoryStream()) {
        Serializer.Serialize(ms, sco);
        return Convert.ToBase64String(ms.ToArray());
    }
}

反序列化:

protected override bool Deserialize(string data)
{
    using(MemoryStream ms = new MemoryStream(Convert.FromBase64String(data)) {
        SerializableContingentOrder sco =
               Serializer.Deserialize<SerializableContingentOrder>(ms)
    }
    return true;
}

【讨论】:

  • 1) 什么是 Serializer.Serialize()?它属于哪个命名空间/程序集? 2)感谢您提供如此全面的答案,但是“BinaryFormatter 或 SoapFormatter 很脆弱”是什么意思?请扩大一点
  • 你不应该提倡反对存储而不是不存储吗? :) 不要搞错了,英语不是我的母语,所以这个问题。
  • @Captain Comic - Serializer 是(根据我的回复)protobuf-net。重新“不存储”,写的是正确的。我不建议将BinaryFormatter 用于存储目的。再脆:marcgravell.blogspot.com/2009/03/…
【解决方案3】:

最简单的方法是用OptionalFieldAttribute 装饰新字段。这并不完美,但它可能适合你的情况。

【讨论】:

  • OptionalField 不适用于 'struct' 类型的数据成员,例如 'Guid'。 “当一个类有结构字段时,OptionalFieldAttribute 将停止工作。”在这里阅读:bytes.com/topic/net/answers/…
【解决方案4】:

从 .NET 2.0 开始,如果您使用 BinaryFormatter,您将获得版本容忍序列化支持。 SoapFormatter 还支持一些版本容错功能,但不是BinaryFormatter 支持的所有功能,更具体地说,不支持无关数据容错。

有关更多信息,您应该查看:

Version Tolerant Serialization

【讨论】:

  • 根据我的经验,BinaryFormatter“版本容错序列化”只是不是。
  • @Marc Gravell,我相信你的话,但你能详细说明你面临的具体问题吗?
  • 同意 Marc,VTS 允许对代码进行一些更改,例如添加可选字段,但很难确定所有后续更改都将是“VTS 兼容”。
猜你喜欢
  • 1970-01-01
  • 2021-05-09
  • 2013-03-15
  • 2020-09-14
  • 2012-06-11
  • 2011-06-07
  • 2017-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多