Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

protobuf-net keeping future fields

I've googled a bit for this now, but haven't been able to determine if protobuf-net or protobuf in general supports forward compatibility in the following sense:

An older version of the object deserializes a new version of the object with a new field, but preserves this field when serializing it back, so the new version of the object doesn't lose the value.

Is this possible with protobuf's?

Many Thanks

like image 613
Damian Avatar asked Jan 24 '14 11:01

Damian


1 Answers

Yes; round-tripping unknown data is supported by most protobuf implementations. Since you specifically tagged protobuf-net - if you are using code-first (i.e. writing classes by hand, which is pretty common with protobuf-net), then you need to provide support for this explicitly. The easiest way to do this is to inherit Extensible. The following shows successful round-trip via a type that knows nothing of the field:

using System;
using System.IO;
using ProtoBuf;

[ProtoContract]
class Foo
{
    [ProtoMember(1)]
    public int X { get;set; }
    [ProtoMember(2)]
    public int Y { get;set; }
}
[ProtoContract]
class Bar : Extensible
{
    [ProtoMember(1)]
    public int A { get;set; } // if declared, needs to be compatible

    // note we don't have a declared field 2 here
}
static class Program
{
    static void Main()
    {
        Foo orig = new Foo { X = 123, Y = 456 }, clone;
        Bar bar;
        using(var ms = new MemoryStream())
        {
            Serializer.Serialize(ms, orig);
            ms.Position = 0;
            bar = Serializer.Deserialize<Bar>(ms);

            Console.WriteLine(bar.A); // 123 // query known data
            int b = Extensible.GetValue<int>(bar, 2); // query unknown data
            Console.WriteLine(b); // 456
        }
        using (var ms = new MemoryStream())
        {
            Serializer.Serialize(ms, bar);
            ms.Position = 0;
            clone = Serializer.Deserialize<Foo>(ms);
        }
        Console.WriteLine(clone.X); // 123
        Console.WriteLine(clone.Y); // 456
    }
}
like image 52
Marc Gravell Avatar answered Sep 28 '22 08:09

Marc Gravell