【问题标题】:protobuf-net : list with null elementsprotobuf-net :具有空元素的列表
【发布时间】:2017-03-23 02:43:38
【问题描述】:
public MyType {

  [ProtoMember(1)]
  public int Index;

  [ProtoMember(2)]
  public string Name;

  public MyType() {
  }

  public MyType(int index, string name) {
    Index = index;
    Name = name;
  }
}

var element0 = new MyType(0,"element index 0");
var element1 = null;
var element2 = new MyType(2,"element index 2");
var list = new List<MyType> {element0, element1, element2}

由于元素索引 1 为 null ,protobuf-net 序列化程序将从序列化字节中省略该元素。

在电线的另一边,发生了一件非常有趣的事情:

protobuf-net 解串器读取字节,得知预期有 3 个元素,但只找到元素索引 0 和 2 的字节。因此它将元素索引 1 创建为 MyType 的空实例。

所以反序列化的列表等价于:

var element0 = new MyType(0,"element index 0");   
var element1 = new MyType(0,null); 
var element2 = new MyType(2,"element index 2");
var list = new List<MyType> {element0, element1, element2}

但这不是预期的。 Null 与空对象不同,具有重复 Index=0 和 Name=null 的元素的存在可能会对处理代码产生严重的不利后果 - 理所当然不应意识到也不关心 serdes 细节。

有解决方法吗?

【问题讨论】:

    标签: list serialization null deserialization protobuf-net


    【解决方案1】:

    基本上,不,没有解决方法,它不是 protobuf-net 中支持的方案。底层协议缓冲区格式(protobuf-net 实现)没有 null 的概念;我无法在常规格式中表示空实例。类列表只是重复的以长度为前缀的节点块,因此(以密集的二进制格式,而不是文本):

    [field 1, length-prefixed] [length prefix] [payload for element index 0]
    [field 1, length-prefixed] [length prefix] [payload for element index 1]
    [field 1, length-prefixed] [length prefix] [payload for element index 2]
    ... etc
    

    对于列表中的空值,我仅有的两个选项是:

    • 忽略它们
    • 将它们视为零长度

    Protobuf-net 目前使用第二种方法,但是:零长度类本质上是new MyType();零长度在协议缓冲区中完全有效且定义明确。

    与其他一些格式不同,实际上没有任何地方可以添加额外的元数据来表示“我是空的”(例如,xml 中的@xsi:nil)。

    可能我可以将其破解到“保留引用”代码中,但我已经检查过,目前不支持空值 - 我接受这有点疏忽,但我还要强调“保留引用”代码不是标准的 protobuf,任何其他库(java、golang 等)可能难以使用该配置;如果您知道您只是在谈论 protobuf-net 和 protobuf-net,我会 提倡。当然,null 支持目前不存在,需要修改 :)

    【讨论】:

    • 谢谢马克。在您的另一篇文章中,我发现了这个解决方法:RuntimeTypeModel.Default[typeof (YourType)][1].SupportNull = true; 这仍然受支持吗?如果是这样,你建议使用它吗?有什么优点/缺点?
    • @BaltoStar 该死的,我都忘记了!随意尝试 - 让我知道它是否有效!
    • 谢谢马克。有没有计划将此功能添加为代理类注释?
    • 在测试设置上下文中,当我为多种类型配置 null 支持时 RuntimeTypeModel.Default[typeof (MyType)][1].SupportNull = true; RuntimeTypeModel.Default[typeof (MyEmbeddedType)][2].SupportNull = true; RuntimeTypeModel.Default[typeof (MySubType)][3].SupportNull = true; 我收到零星的 null ref 错误。奇怪的是,它似乎取决于所选原始索引的值和顺序。
    • RuntimeTypeModel.Default... 方法对我有用。在 protomember 属性中可用会很好。
    猜你喜欢
    • 1970-01-01
    • 2011-01-23
    • 1970-01-01
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 2013-09-28
    • 1970-01-01
    相关资源
    最近更新 更多