为了账号安全,请及时绑定邮箱和手机立即绑定

序列化包含列表的对象时 ProtoBuf-net 无效行为

序列化包含列表的对象时 ProtoBuf-net 无效行为

C#
波斯汪 2022-01-09 15:12:36
我很难解释以下示例中的行为:[ProtoContract]public class Class1Proto{    [ProtoMember(1)]    public int data1 = 1;    [ProtoMember(2)]    public string data2 = "MYRANDOMSTRING";}[ProtoContract]public class ProtoChunk{    [ProtoMember(1)]    public List<Class1Proto> arr = new List<Class1Proto>();    public const int PageSize = 4096;}用法:    byte[] page = new byte[ProtoChunk.PageSize];    ProtoChunk originalData = new ProtoChunk();    for (int i = 0; i < 100; i++)    {        Class1Proto p = new Class1Proto();        p.data1 = i * 2;        p.data2 = (i * 2).ToString();        originalData.arr.Add(p);    }    using (var memStream = new MemoryStream(page, writable:true))    {        Serializer.SerializeWithLengthPrefix(memStream, originalData, PrefixStyle.Fixed32);    }    using (var memStream = new MemoryStream(page, writable:false))    {        ProtoChunk deserializedData = Serializer.DeserializeWithLengthPrefix<ProtoChunk>(memStream, PrefixStyle.Fixed32);    }我的期望是这样,originalData并且deserializedData应该是相同的。他们大多是除此之外deserializedData.arr[0].data1 == 1 while originalData.arr[0].data1 == 0。所有其他对象都是相同的,甚至包括originalData.arr[0].data2 and deserializedData.arr[0].data2(字符串字段)。
查看完整描述

1 回答

?
一只甜甜圈

TA贡献1836条经验 获得超5个赞

protobuf-net 假定“隐式零默认值”——即除非另有说明,否则成员的默认值为零,这意味着:不传输零。这不是纯粹任意的——这实际上是“proto3”规范(嗯……或多或少;在“proto3”中,零是唯一允许的默认值)。

您的代码 - 特别是属性初始化程序 - 就好像它具有默认值 1,因此:当不传输零时,构造函数仍会应用 1,这将成为值(protobuf 中的反序列化是“合并”操作 - 预先存在的值被保留,再次符合规范)。

选项:

  • 告诉 protobuf-net 你的默认值 - 添加[DefaultValue(1)]到属性中

  • 告诉 protobuf-net 不要运行构造函数(和属性初始化程序) - 添加SkipConstructor = true[ProtoContract]

  • 告诉 protobuf-net 不要假设这种行为: RuntimeTypeModel.Default.ImplicitZeroDefault = false;

  • 添加你自己的条件序列化回调(如果你真的想我可以举个例子)

我个人会使用第一个选项。


查看完整回答
反对 回复 2022-01-09
  • 1 回答
  • 0 关注
  • 199 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信