18

If I have object A and B both contain some field serialized field F, and both point to the same serializable object C. Does protobuf-net serialize by reference or serialize by value? When the object graph is deserialized, does protobuf-net generate 2 separate objects for A.F and B.F? I'm asking because I want to know if serialization preserves reference equality.

Nemo
  • 70,042
  • 10
  • 116
  • 153
jz87
  • 9,199
  • 10
  • 37
  • 42

1 Answers1

21

The raw "protobuf" spec, a defined by Google, is a tree serializer (like XmlSerializer). So by default you would get C serialized twice, and two different objects when deserialized.

However, this is such a common question that in "v2" I provide this as an opt-in behaviour; note you should only use this for protobuf-net to protobuf-net, as other clients will not expect this configuration (although it remains a valid protobuf stream).

For example (using attributes, bit you can also use a runtime model instead):

[ProtoContract]
public class A {
    ...
    [ProtoMember(5, AsReference=true)]
    public C Foo {get;set;}
}

[ProtoContract]
public class B {
    ...
    [ProtoMember(7, AsReference=true)]
    public C Bar {get;set;}
}

[ProtoContract]
public class C {...}

This will serialize the instance once, generating an id unique in the output. When deserialized, the same object will be used in both places.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 2
    Wow, I honestly didn't expect the by reference feature, since I figured the underlying format probably doesn't support it, given the original purpose of PB. This is really awesome. – jz87 Jun 11 '11 at 09:31
  • 2
    Just as a followup question though, if I serialize an array by reference, does every element of that array get serialized by reference as well or just the top level array itself? – jz87 Jun 11 '11 at 09:39
  • @jz87 good question. I honestly would need to check and get back to you – Marc Gravell Jun 11 '11 at 10:38
  • 2
    It looks like current protobuf-net v2 revision 445 supports only class (or array element) reference equality. When you serialize two reference equal collections, then after deserialization you get two distinct in reference equality sense collections, but all elements of these collection will be reference equal. – Bartosz Pierzchlewicz Oct 06 '11 at 11:52
  • Remember that "AsReference = true" should be present on all references to the object which should be serialized in only 1 copy - which includes collections containing it and navigational properties. – too Nov 27 '14 at 13:53
  • Remember also that if you define a runtime model using surrogates and "AsReference=true" you'll get an exception 'A reference-tracked object changed reference during deserialization'. – ilCosmico Feb 20 '19 at 11:26