Что означает атрибут ProtoInclude (в protobuf-net)
-
09-09-2019 - |
Вопрос
в ПротоБуф-Нет реализация, что означает ПротоИнклюд Атрибут означает и что он делает?
Пример был бы оценен.
я видел это в этом посте и я не уверен, что он делает.Пример был:
[Serializable,
ProtoContract,
ProtoInclude(50, typeof(BeginRequest))]
abstract internal class BaseMessage
{
[ProtoMember(1)]
abstract public UInt16 messageType { get; }
}
[Serializable,
ProtoContract]
internal class BeginRequest : BaseMessage
{
[ProtoMember(1)]
public override UInt16 messageType
{
get { return 1; }
}
}
Кроме того, есть ли способ создать такое наследование с помощью прототип инструмент?
Решение
Извините, я не хотел это пропустить - увы, я не все вижу.
Учитывая специфику вопроса, я предполагаю, что вы хотя бы поверхностно знакомы с .proto;поправьте меня, если я ошибаюсь.
[ProtoInclude]
работает очень похоже [XmlInclude]
для XmlSerializer
- или [KnownType]
для DataContractSerializer
- это позволяет распознавать подклассы типа во время (де)сериализации.Единственным дополнительным моментом является то, что для идентификации каждого подтипа требуется тег (номер) (который должен быть уникальным и не конфликтовать ни с одним из полей родительского типа).
Протоген:неа;базовая спецификация (от Google) не предусматривает наследование совсем, поэтому у protogen (через .proto) нет механизма для выражения этого.protobuf-net обеспечивает поддержку наследования как расширение, но делает это таким образом, чтобы сообщения оставались совместимыми с другими реализациями.В толчке, может быть Я мог бы добавить поддержку протогена через новые свойства расширения в спецификации Google, но я еще этого не сделал.
Так;посмотреть пример;который выражает отношения наследования между BaseMessage
и BeginRequest
;независимо от того, делаете ли вы:
Serialize<BaseMessage>(...)
Serialize<BeginRequest>(...)
- в любом случае, он начнется с базы (
BaseMessage
) и работайте вверх;что не так точно правда - пишет данные начиная сBeginRequest
(чтобы он знал, что у нас естьBeginRequest
как можно раньше во время десериализации).Важно то, что поля из любых родительских типов контрактов включены, и сериализатор просматривает действительный переданный объект, а не только тот тип, который вы сказать это.
Аналогично, при десерилизации, независимо от того, используете ли вы:
Deserialize<BaseMessage>(...)
Deserialize<BeginRequest>(...)
вы получите тип, который вы действительно сериализовали (предположительно, BeginRequest
).
Под капотом, в целях совместимости (со спецификацией буферов широкого протокола), это похоже на запись чего-то вроде (простите за ошибки, мой .proto заржавел):
message BaseMessage {
optional BeginRequest beginRequest = 50;
optional uint32 messageType = 1;
}
message BeginRequest {
}
(переопределение, вероятно, не должно указывать [ProtoMember]
, кстати.
Обычно он записывает поля в порядке возрастания тегов, но для обеспечения эффективной десериализации движок нахально предпочитает записывать данные подкласса. первый (что явно разрешено спецификацией), т.е.он пишет что-то вроде (вам придется представить двоичный файл...):
[tag 50, string][length of sub-message][body of sub-message][tag 1, int][value]
(в этом случае тело подсообщения пустое)
Это покрывает это?