Извините, я не хотел пропустить это - увы, я не все вижу.
Учитывая особенности вопроса, я собираюсь предположить, что вы, по крайней мере, немного знакомы с .proto; поправьте меня, если я ошибаюсь.
[ProtoInclude]
работает так же, как [XmlInclude]
для XmlSerializer
- или [KnownType]
для DataContractSerializer
- это позволяет распознавать подклассы типа во время (де) сериализации. Единственная дополнительная вещь - это то, что ему нужен тег (число) для идентификации каждого подтипа (который должен быть уникальным и не конфликтовать ни с одним из полей родительского типа).
Re протоген: нет; Базовая спецификация (от Google) вообще не предусматривает наследования , поэтому у protogen (через .proto) нет механизма для выражения этого. Protobuf-net обеспечивает поддержку наследования в виде расширения , но делает это таким образом, чтобы сообщения оставались совместимыми с другими реализациями. Одним нажатием возможно Я мог бы добавить поддержку протогенов через новые свойства расширения в спецификации Google, но я еще этого не сделал.
Итак, посмотреть на пример; которая выражает наследственные отношения между BaseMessage
и BeginRequest
; независимо от того, делаете ли вы:
Serialize<BaseMessage>(...)
Serialize<BeginRequest>(...)
- в любом случае, он начнется у основания (
BaseMessage
) и будет работать вверх; который не точно true - он записывает данные , начиная с BeginRequest
(чтобы он знал, что у нас есть BeginRequest
как можно раньше во время десериализации). Важно то, что поля из любых родительских типов контрактов включены, и сериализатор смотрит на переданный фактический объект, а не только на тот тип, который вы говорите , это.
Аналогично, во время десерилизации, независимо от того, используете ли вы:
Deserialize<BaseMessage>(...)
Deserialize<BeginRequest>(...)
вы получите тип, который вы на самом деле сериализовали (предположительно BeginRequest
).
Под капотом в целях совместимости (со спецификацией широких протокольных буферов) это похоже на запись чего-то вроде (простите за любые ошибки, мой .proto ржавый):
message BaseMessage {
optional BeginRequest beginRequest = 50;
optional uint32 messageType = 1;
}
message BeginRequest {
}
(переопределение, вероятно, не должно указывать [ProtoMember]
, кстати.
Как правило, он будет писать поля в порядке возрастания тегов, но для эффективной десериализации механизм нахально выбирает запись данных подкласса first (что явно разрешено спецификацией) - т.е. он что-то пишет как (вы должны представить двоичный файл ...):
[tag 50, string][length of sub-message][body of sub-message][tag 1, int][value]
(в этом случае тело дополнительного сообщения пустое)
Это покрывает это?