我有一个文件,其中包含字节格式的 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/