从c++中反序列化protobuf和在c#中重新序列化会得到不同的输出

本文关键字:输出 序列化 反序列化 c++ protobuf 和在 | 更新日期: 2023-09-27 18:07:54

我有一个文件,其中有一个字节格式的protobuf消息,当我读取文件并反序列化protobuf时,它工作得很好(我可以读取对象字段并且它们是正确的),然而,当我重新序列化它并将其保存回文件时,一些字节与原始不同(导致兼容性问题)。

更具体地说,在字符串的后面和bool的前面都添加了字节' 1800 '。

我试着从protobuf-net中使用DataFormat选项来获得与原始结果完全相同的结果,但无济于事。

有没有人知道在protobuf-net关于保存字符串或bool可以解释额外的2字节的任何选项?

同时,ulong也以不同的字节保存。

我无法控制原始文件,我只知道它是用c++编译/序列化的

我的目标是通过c#序列化来重新创建完全相同的文件(按字节顺序),因此它与c++序列化的文件相同。

从c++中反序列化protobuf和在c#中重新序列化会得到不同的输出

这取决于如何处理属性。默认情况下,

protogen -i:my.proto -o:my.cs

生成简单的属性,形式为:

private bool _some_value = default(bool);
[global::ProtoBuf.ProtoMember(3, IsRequired = false, Name=@"some_value",
    DataFormat = global::ProtoBuf.DataFormat.Default)]
[global::System.ComponentModel.DefaultValue(default(bool))]
public bool some_value
{
  get { return _some_value; }
  set { _some_value = value; }
}

这对于大多数场景来说都很好,但是并不完全支持每个"实际指定的值"场景。

但是,你可以这样做:

protogen -i:my.proto -o:my.cs -p:detectMissing

生成更彻底的:

private bool? _some_value;
[global::ProtoBuf.ProtoMember(3, IsRequired = false, Name=@"some_value",
    DataFormat = global::ProtoBuf.DataFormat.Default)]
public bool some_value
{
  get { return _some_value?? default(bool); }
  set { _some_value = value; }
}
[global::System.Xml.Serialization.XmlIgnore]
[global::System.ComponentModel.Browsable(false)]
public bool some_valueSpecified
{
  get { return this._some_value != null; }
  set { if (value == (this._some_value== null))
      this._some_value = value ? this.some_value : (bool?)null; }
}
private bool ShouldSerializesome_value() { return some_valueSpecified; }
private void Resetsome_value() { some_valueSpecified = false; }

它完全支持跟踪显式赋值,包括对大多数ui绑定和序列化框架的支持(不仅仅是protobuf-net)。

2字节的差异仅仅是"false,由于隐式默认值而未序列化"answers"false,已知被显式指定为false,因此已序列化"之间的差异。

所以修复是:使用protogen时包括-p:detectMissing