Наследование в Protobuf-net: ProtoInclude и совместимость - PullRequest
4 голосов
/ 11 ноября 2011

Как описано в этом посте , мы можем использовать атрибут ProtoInclude для управления сериализацией иерархии классов.И если мы будем использовать только protobuf-net, он будет работать в обоих направлениях.Но проблема возникает, когда мы пытаемся десериализовать сообщения, сериализованные «внешними» реализациями унаследованных протокольных буферов, напр.Java и т. Д.

Как уже упоминалось в этом посте выше, Protobuf-net распознает иерархию классов по «обращенным» последовательностям байтов, когда дочерние поля классов сериализуются перед родительскими.Но устаревший код сериализует их в «правильном» порядке, и protobuf-net создает исключение «Невозможно привести объект типа« А »к типу B». исключение во время десериализации.В обратном направлении все работает нормально, унаследованный код может десериализовать «иерархические» сообщения, создаваемые библиотекой protobuf-net.

Я не могу повлиять на порядок сериализации байтов на противоположной стороне канала.Как я могу правильно десериализовать этот тип сообщений на стороне .NET protobuf-net?

Обновление: примеры кода

На нашем конце строки у нас есть оригинальные иерархические классы protobuf-net:

[ProtoContract, ProtoInclude(10, typeof(B))]
public class A
{
    [ProtoMember(1)]
    public int Age;
}

public class B : A
{
    [ProtoMember(2)]
    public int Balls;
}

На другом концеклассы строк генерируются с использованием файла .proto:

message B {
    optional int32 balls = 2;   
}

message A {
    optional int32 age = 1; 
    optional B b = 10;
}

Пример сгенерированных классов, мы могли бы использовать генератор protobuf-net для их создания для .NET:

[ProtoContract]
public class A_generated
{
    [ProtoMember(1)]
    public int Age;

    [ProtoMember(10)]
    public B b;
}

[ProtoContract]
public class B_generated 
{
    [ProtoMember(2)]
    public int Balls;
}

Так что теперь,давайте сериализуем и десериализуем класс B:

  • Сериализуем и десериализуем обратно оригинальные классы - ОК
  • Сериализуем и десериализуем обратно созданные классы - ОК
  • Сериализация оригинал и десериализация как сгенерированный - ОК
  • Сериализация сгенерированный и десериализация как оригинал - FAIL , "Невозможно привести объект типа 'A' к типу 'B'." исключение

Я исследовал полученные байты и обнаружилразница - порядка байтов .

Пример: пусть Age = 10 и Balls = 23.Затем:

  • оригинал B, сериализованный: [82, 2, 16, 23, 8, 10], может быть десериализован с использованием обоих как оригинал как сгенерировано классов;
  • сгенерировано B сериализовано: [8, 10, 82, 2, 16, 23], НЕ может быть десериализовано с использованием protobuf-net original классы выше.

Надеюсь, теперь все достаточно ясно, и я хочу получить положительный ответ: да, есть способ использовать ProtoInclude и десериализовать универсальные классы.

1 Ответ

2 голосов
/ 12 ноября 2011

Edit: это должно поддерживаться в v2 начиная с r616.


Цитировать из protobuf / Java-учебник :

Don 'Однако не стоит искать средства, похожие на наследование классов - протокольные буферы этого не делают.

Итак: что бы вы ни использовали локально для подмены наследования локально, я бы посоветовал: используйте это и здесь.Вы можете запустить существующий .proto через protogen, например.

Если вы можете быть очень точными в отношении компоновки с обеих сторон (например, .proto, например), я мог бы посоветовать дальше.

...