I'm using protobuf-net for serializing a number of types, some of which are inherited from a base type. I know that the Protocol Buffers spec does not support inheritance, and that the support in protobuf-net is basically a workaround because of that.
Rather than using the protobuf-net attributes I am configuring a custom RuntimeTypeModel
, and using the Add
and AddSubType
methods. What I'm not quite grasping is how I should determine which numbers to use for the field numbers passed to the AddSubType
method (aka the number that would be used in a ProtoInclude
attribute).
This SO question and several others like it do not really describe how the field numbers are chosen, and indeed I've seen many different variations: 4 & 5; 7 & 8; 101 & 102 & 103; 20; 500; etc. Obviously they're chosen so as not to clash with one another, but how are they chosen? What determines which number to start at?
The following code is a contrived example but it does match my heirarchy (a base Event
type that has two derived subtypes).
using System;
using System.Collections.Generic;
using ProtoBuf.Meta;
namespace Test
{
public sealed class History
{
public History()
{
Events = new List<Event>();
}
public ICollection<Event> Events { get; private set; }
}
public enum EventType
{
ConcertStarted, ConcertFinished, SongPlayed
}
public class Event
{
public EventType Type { get; set; }
public DateTimeOffset Timestamp { get; set; }
}
public sealed class Concert : Event
{
public string Location { get; set; }
}
public sealed class Song : Event
{
public string Name { get; set; }
}
public static class ModelFactory
{
public static RuntimeTypeModel CreateModel()
{
RuntimeTypeModel model = TypeModel.Create();
model.Add(typeof(DateTimeOffset), applyDefaultBehaviour: false)
.SetSurrogate(typeof(DateTimeOffsetSurrogate));
model.Add(typeof(History), applyDefaultBehaviour: false)
.Add("Events");
model.Add(typeof(Concert), applyDefaultBehaviour: false)
.Add("Location");
model.Add(typeof(Song), applyDefaultBehaviour: false)
.Add("Name");
model.Add(typeof(Event), applyDefaultBehaviour: false)
.Add("Type", "Timestamp")
.AddSubType(???, typeof(Concert))
.AddSubType(???, typeof(Song));
return model;
}
}
}
There is no requirement other than:
Other than that: it doesn't matter. Leaving a gap might make it easier to add additional fields to the parent type without accidentally creating conflicts, but: smaller field-numbers are cheaper to serialize, so if possible: prefer small numbers
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With