Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protobuf-Net Empty List

Came across protobuf-net, awesome! I have a question regarding serialization of empty lists.

I start by declaring the object I want to serialize:

[ProtoContract]
class TestClass
{
    [ProtoMember(1)]
    List<int> _listOfInts = new List<int>();

    public TestClass() { }

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

If _listOfInts is empty (but not null) when I deserialse this object is will always be null. This makes sense looking at the protobuf convention and I currently work around this by adding the following method:

[ProtoAfterDeserialization]
private void OnDeserialize()
{
    if (_listOfInts == null)
        _listOfInts = new List<int>();
}

My question is whether I can achieve this same functionality in a more concise fashion, possibly with an additional attirbute which will initialise null/empty objects as empty instead of null?

like image 210
CanCan Avatar asked May 05 '13 21:05

CanCan


2 Answers

There's a fundamental issue here in terms of how protobuf encodes data: the list itself does not appear in the data - just the elements. Because of this, there is simply nowhere obvious to store information about the list. It can be spoofed by sending a Boolean using conditional serialization, but frankly that is a bit hacky and ugly - and adds complexity. Personally, I strongly advise abstracting away from lists that could ever be null. For example:

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

Or

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

And note that this advice isn't just about serialization: it is about avoiding arbitrary null-reference-exceptions. People don't usually expect sub-collections to be null.

like image 91
Marc Gravell Avatar answered Nov 03 '22 20:11

Marc Gravell


If you are trying to protect against a null list you could try lazy loading in the property getter.

public List<int> ListOfInts
{
    get { return _listOfInts ?? (_listOfInts = new List<int>()); }
    set { _listOfInts = value; }
}

This way you can just allow the serializer to return null.

like image 21
Jras Avatar answered Nov 03 '22 20:11

Jras