Reputation: 8977
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}
Since element index 1 is null , protobuf-net
serializer will omit that element from the serialized bytes.
On the other side of the wire, something very interesting happens :
protobuf-net
deserializer reads the bytes, learns that 3 elements are expected, but only finds bytes for elements index 0 and 2. So it creates element index 1 as an empty instance of MyType
.
So the deserialized list is equivalent to :
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}
But this is not what is expected. Null is not the same thing as an empty object, and the presence of an element with duplicate Index=0 and Name=null can have serious adverse consequences for the processing code - which rightfully should not be aware of nor concerned with serdes details.
Is there a workaround ?
Upvotes: 4
Views: 2078
Reputation: 1062780
Basically, no, there's no workaround for this and it is not a supported scenario in protobuf-net. The underlying protocol buffers format (which protobuf-net implements) has no concept of null; there is no way for me to represent a null instance inside the regular format. A list of classes is simply a repeated chunk of length-prefixed nodes, so (in a dense binary format, not text):
[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
The only two options I have for nulls in a list are:
Protobuf-net currently uses the second approach, but: a zero-length class is essentially new MyType()
; zero-length is perfectly valid and well-defined in protocol buffers.
Unlike some other formats, there isn't really anywhere I can add extra metadata to say "I'm a null" (@xsi:nil
in xml, for example).
It might be possible for me to hack this into the "preserve references" code, but I've checked, and support for nulls isn't there currently - I accept that this is a bit of an oversight, but I would also emphasize that the "preserve references" code is not standard protobuf, and any other libraries (java, golang, etc) may have difficulty consuming that configuration; I would only advocate that if you know you're only talking protobuf-net to protobuf-net. And of course, the null support doesn't currently exist, and would need hacking in :)
Upvotes: 2