c# - 从 C++ 反序列化 protobuf 并在 C# 中重新序列化给出不同的输出

标签 c# c++ protocol-buffers protobuf-net

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

更具体地说,在字符串之后和 bool 值之前添加了字节“18 00”。

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

有谁知道 protobuf-net 中关于保存字符串或 bool 值的任何选项,这可以解释额外的 2 个字节?

此外,ulong 的字节保存方式也不同。

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

我的目标是通过在 C# 中序列化来重新创建完全相同的文件(按字节),因此它与通过 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 绑定(bind)和序列化框架(不仅仅是 protobuf-net)。

2个字节的区别只是“false,由于隐式默认值而未序列化”和“false,已知被显式指定为false,从而被序列化”之间的区别。

所以解决方法是:在使用 protogen 时包含 -p:detectMissing

关于c# - 从 C++ 反序列化 protobuf 并在 C# 中重新序列化给出不同的输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24145882/

相关文章:

c# - 线程和隐式内存屏障

c# - 如何注册一个新的 List<IChecker> 到 Autofac ContainerBuilder

c++ - 为什么推导出这里的类型是uint32_t呢?

c++ - 将线性代数库与 Boost::Units 相结合

c++ - 命令模式 : how can I do continuous actions?(例如移动对象)

c# - WP7 中的 Protobuf-net 抛出 FieldAccessExceptions

c# - 下拉列表中的项目重复

java - 将参数添加到 DialogFlow Java API 的 QueryInput 上的 EventInput

python - Flask - 处理表单文件并上传到 AWS S3 而不保存到文件

c# - 当类实现 Equals 和 GetHashCode 时,如何使用对象引用作为 C# 字典中的键?