Protobuf-Net 空列表

Posted

技术标签:

【中文标题】Protobuf-Net 空列表【英文标题】:Protobuf-Net Empty List 【发布时间】:2013-05-05 21:17:53 【问题描述】:

遇到了protobuf-net,太棒了!我有一个关于空列表序列化的问题。

我首先声明我要序列化的对象:

[ProtoContract]
class TestClass

    [ProtoMember(1)]
    List<int> _listOfInts = new List<int>();

    public TestClass()  

    public List<int> ListOfInts
    
        get  return _listOfInts; 
        set  _listOfInts = value; 
    

如果我反序列化时 _listOfInts 为空(但不为空),则此对象将始终为空。看看 protobuf 约定是有道理的,我目前通过添加以下方法来解决这个问题:

[ProtoAfterDeserialization]
private void OnDeserialize()

    if (_listOfInts == null)
        _listOfInts = new List<int>();

我的问题是我是否可以以更简洁的方式实现相同的功能,可能还有一个额外的属性将 null/empty 对象初始化为空而不是 null?

【问题讨论】:

【参考方案1】:

这里有一个关于 protobuf 如何编码数据的基本问题:列表本身不会出现在数据中 - 只是元素。因此,根本没有明显的地方可以存储有关列表的信息。可以通过使用条件序列化发送布尔值来欺骗它,但坦率地说,这有点 hacky 和丑陋 - 并增加了复杂性。就个人而言,我强烈建议从可能为空的列表中抽象出来。例如:

private readonly List<Foo> items = new List<Foo>();
[ProtoMember(1)]
public List<Foo> Items  get  return items;  

或者

private List<Foo> items;
[ProtoMember(1)]
public List<Foo> Items  get  return items ?? (items = new List<Foo>());  

请注意,此建议不仅仅是关于序列化:它是关于避免任意空引用异常。人们通常不希望子集合为空。

【讨论】:

您有什么理由不初始化私人物品字段上的集合吗?我可以看到,如果您还没有访问 Items 属性的 getter,那么您并没有挂在空集合引用上,而是每次都在为空检查付出代价。只是情景吗?【参考方案2】:

如果您试图防止出现空列表,您可以尝试在属性 getter 中延迟加载。

public List<int> ListOfInts

    get  return _listOfInts ?? (_listOfInts = new List<int>()); 
    set  _listOfInts = value; 

这样你就可以让序列化器返回 null。

【讨论】:

这是我没有考虑过的一种可能性,如果可以的话,我会投票给你。不过,我仍然主要想知道是否有一个属性可以为我做到这一点。 您是否尝试过 [DefaultValue] 属性?不确定是否可以初始化列表,但值得一试。 @Jras 我确实考虑过添加这样的内容,但每次我查看它时,事实证明它实际上使人们的代码变得更糟,而不是更好 @Marc Gravell 我同意,如果列表永远不应为空,则应在属性中而不是在序列化程序中处理。

以上是关于Protobuf-Net 空列表的主要内容,如果未能解决你的问题,请参考以下文章

Protobuf-Net 总是反序列化一个空列表

protobuf-net v3 中的数组或列表中的空对象

protobuf-net 序列化返回空数组

Protobuf-net:嵌套的 IEnumerable 对象

ProtoBuf-Net 错误消息 - “不支持嵌套或锯齿状列表和数组”

Protobuf-net:如何调试“不支持嵌套或锯齿状列表和数组”