哪个序列化程序最容易对.NET中序列化类型的更改感到宽容?

时间:2009-10-21 17:17:18

标签: c# .net serialization protocol-buffers

我注意到XmlSerializer更容易添加新成员,删除现有成员等等。

当我使用BinaryFormatter执行此操作并尝试反序列化旧数据时,它引发了异常。

还有哪些其他替代方案可供宽容选项,即不抛出异常的选项只使用默认值,跳过它们等等?

协议缓冲在这方面是否宽容?

6 个答案:

答案 0 :(得分:4)

你提到二进制文件,BinaryFormatter的确是very brittle。问题是BinaryFormatter是基于类型和字段的。相反,您需要基于合同的序列化程序,例如XmlSerialzierDataContractSerializer(3.0)等。

或者对于二进制文件,protobuf-net是Google的“协议缓冲区”有线格式的C#实现,但是在.NET行中重新实现; (注意:我是作者......)。

它(与其他人一样)基于数据协定,但它不是<CustomerName>asdasd</CustomerName>等,而是使用数字标签来识别事物;这样:

[ProtoContract]
public class Customer {
    [ProtoMember(1)]
    public string Name {get;set;}

    // ...
}

当你添加更多成员时,你会给他们新的唯一数字;这可以保持它的可扩展性,而不依赖于任何名称等。加上它非常快;-p与XmlSerializer一样,它会忽略它不期望的东西(或者它可以存储它们以安全地往返于意外的数据),并支持相同的默认事物。您甚至可以使用现有的xml属性:

[XmlType]
public class Customer {
    [XmlElement(Order=1)]
    public string Name {get;set;}

    // ...
}

我可以整天谈论这个话题,所以我最好在[太晚]之前闭嘴。

答案 1 :(得分:2)

您可以从ISerializable继承您的类并定义自定义GetObjectData。我没有对此进行过测试,但是这样的类可能会从二进制格式中反序列化,即使此后已对该类进行了更改。

修改

我刚刚确认这是有效的。您可以使用下面的示例代码来明确定义对象的序列化和反序列化方式。然后由您决定使这些方法适用于您的类的旧版本。我通过将一个Cereal实例序列化为二进制文件来测试它,然后对类进行更改并重新读取文件以进行反序列化。

[Serializable]
private class Cereal : ISerializable
{
    public int Id { get; set; }
    public string Name { get; set; }

    public Cereal()
    {
    }

    protected Cereal( SerializationInfo info, StreamingContext context)
    {
        Id = info.GetInt32 ( "Id" );
        Name = info.GetString ( "Name" );
    }

    public void GetObjectData( SerializationInfo info, StreamingContext context )
    {
        info.AddValue ( "Id", Id );
        info.AddValue ( "Name", Name );
    }
}

答案 2 :(得分:0)

我强烈建议您进行自己的序列化,以便您拥有与语言方案无关的明确定义的文件格式。

答案 3 :(得分:0)

我实际上发现二进制格式化程序从长远来看是最持久的。

它提供了出色的向前兼容性。也就是说,如果将文件升级到新版本,它将无法与旧的反序列化器一起使用。

我通常创建一些我想用于序列化的简单数据类。当我需要更改类时,我实现了OnDeserialized / OnDeserializing方法。这样可以升级数据。

二进制格式化程序不需要为您的属性设置公共setter,这对我来说有时是个大问题。

    [Serializable]
    public class data
    {
      private int m_MyInteger;
      // New field
      private double m_MyDouble;

      [OnDeserializing]
      internal void OnDeserializing(StreamingContext context)
      {
        // some good default value
        m_MyDouble = 5;
      }

      public int MyInteger
      {
        get{ return m_MyInteger; }
        set { m_MyInteger = value; }
      }
   }

答案 4 :(得分:0)

我认为以下帖子可以帮到你。我也同意那些说要编写自己的序列化程序的人。它比xsd.exe生成的代码更好。

请参阅下面的帖子:

Serialization and Deserialization into an XML file, C#

答案 5 :(得分:0)

您还可以查看OptionalFieldAttributeSerializableAttribute / NonSerializedAttribute以及BinaryFormatterSoapFormatter

一起使用

...版本1

[Serializable]
public class MyClass
{
    public string field1;

    [NonSerialized]
    public string field2;
}

...版本2

[Serializable]
public class MyClass
{        
    public string field1;

    [NonSerialized]
    public string field2;

    [OptionalField]
    public string field3;
}