Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does protocol buffers support serialization of object graphs with shared references?

Please, observe the following simple program (based on the example from the protobuf-net project v1 wiki):

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using ProtoBuf;

namespace HelloProtoBuf
{
  [ProtoContract]
  class Person
  {
    [ProtoMember(1)]
    public int Id { get; set; }
    [ProtoMember(2)]
    public string Name { get; set; }
    [ProtoMember(3)]
    public Address Address { get; set; }
  }
  [ProtoContract]
  class Address
  {
    [ProtoMember(1)]
    public string Line1 { get; set; }
    [ProtoMember(2)]
    public string Line2 { get; set; }
  }


  class Program
  {
    static void Main(string[] args)
    {
      var person = new Person
      {
        Id = 12345,
        Name = "Fred",
        Address = new Address
        {
          Line1 = "Flat 1",
          Line2 = "The Meadows"
        }
      };
      var person2 = new Person
      {
        Id = 4553,
        Name = "Nadya",
        Address = person.Address
      };
      var persons = new List<Person> { person, person2 };
      Debug.Assert(ReferenceEquals(persons[0].Address, persons[1].Address));

      using (var file = File.Create("persons.bin"))
      {
        Serializer.Serialize(file, persons);
      }
      List<Person> persons2;
      using (var file = File.OpenRead("persons.bin"))
      {
        persons2 = Serializer.Deserialize<List<Person>>(file);
      }
      Debug.Assert(ReferenceEquals(persons2[0].Address, persons2[1].Address));
    }
  }
}

The second assertion fails. Is this a bug in the protobuf-net implementation or is it that protocol buffers simply does not support object graphs with shared references?

Thanks.

like image 557
mark Avatar asked May 19 '11 19:05

mark


1 Answers

protocol-buffers itself does not support this - so no, it is not a bug. Indeed, XmlSerializer and DataContractSerializer* would do the same (and probably so would JavaScriptSerializer and JSON.NET).

However, it is a common request, so this is supported in protobuf-net v2 (basically: I cheat). Just change it to:

    [ProtoMember(3, AsReference=true)]
    public Address Address { get; set; }

(and use the v2 dll that I'm uploading in about 5 minutes, or build from code)


*=caveat: DataContractSerializer does support references, but only if you use a specific constructor; it is disabled by default

like image 64
Marc Gravell Avatar answered Nov 18 '22 10:11

Marc Gravell