Я знаю, что это старый вопрос, но я столкнулся с этим недавно.То, как я обошел это, - это использование фасадов и решений во время выполнения для сериализации.Таким образом, я могу исключить / обновить поле до нового типа, при этом старые и новые сообщения будут корректно обрабатывать его.
Я использую protobuf.net от Marc Gravell (v2.3.5) и C #, но теорияФасады подойдут для любого языка и оригинальной реализации Google для protobuf. * 1003 *
В моем старом классе была метка времени DateTime, которую я хотел изменить, чтобы включить «Kind» (анахронизм .NET).Добавление этого факта означало, что оно сериализовалось в 9 байтов вместо 8, что было бы серьезным изменением сериализации!
[ProtoMember(3, Name = "Timestamp")]
public DateTime Timestamp { get; set; }
Основой protobuf является НИКОГДА не менять прототипы!Я хотел прочитать старые сериализованные двоичные файлы, что означало «3», чтобы остаться.
Итак,
Я переименовал старое свойство и сделал его закрытым (да, он все еще может десериализоваться через отражениемагия), но мой API больше не показывает его пригодность!
[ProtoMember(3, Name = "Timestamp-v1")]
private DateTime __Timestamp_v1 = DateTime.MinValue;
Я создал новое свойство Timestamp с новым идентификатором прото и включил DateTime.Kind
[ProtoMember(30002, Name = "Timestamp", DataFormat = ProtoBuf.DataFormat.WellKnown)]
public DateTime Timestamp { get; set; }
Iдобавлен метод «AfterDeserialization» для обновления нашего нового времени, в случае старых сообщений
[ProtoAfterDeserialization]
private void AfterDeserialization()
{
//V2 Timestamp includes a "kind" - we will stop using __Timestamp - so keep it up to date
if (__Timestamp_v1 != DateTime.MinValue)
{
//Assume the timestamp was in UTC - as it was...
Timestamp = new DateTime(__Timestamp_v1.Ticks, DateTimeKind.Utc) //This is for old messages - we'll update our V2 timestamp...
}
}
Теперь у меня есть старые и новые сообщения, сериализованные / десериализованные правильно, и моя метка времени теперь включает DateTime.Kind!Ничего не сломано.
Однако это означает, что ОБА поля будут во всех новых сообщениях, поступающих в будущем.Итак, последний штрих - использовать решение о сериализации во время выполнения, чтобы исключить старую метку времени (обратите внимание, что это не сработает, если используется обязательный атрибут protobuf !!!)
bool ShouldSerialize__Timestamp_v1()
{
return __Timestamp_v1 != DateTime.MinValue;
}
И это все.У меня есть хороший модульный тест, который делает его из конца в конец, если кто-то захочет ...
Я знаю, что мой метод основан на магии .NET, но я считаю, что концепция может быть переведена на другие языки....