20

ProtoBuf-Net实现中,ProtoInclude属性是什么意思,它有什么作用?

一个例子将不胜感激。

在这篇文章中看到了它,但我不确定它的作用。这个例子是:

[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; }
    }
}

另外,有没有办法使用protogen工具生成这种继承?

4

1 回答 1

27

对不起,我不是故意错过这个 - 唉,我没有看到一切。

鉴于问题中的细节,我将假设您至少对 .proto 非常熟悉;如果我错了,请纠正我。

[ProtoInclude]工作原理很像[XmlInclude]for XmlSerializer- 或[KnownType]for DataContractSerializer- 它允许它在(反)序列化期间识别类型的子类。唯一额外的事情是它需要一个标签(数字)来标识每个子类型(必须是唯一的,并且不与父类型中的任何字段冲突)。

再原生质:不;底层规范(由 google 提供)根本没有提供继承,因此 protogen(通过 .proto)没有表达这一点的机制。protobuf-net 作为扩展提供继承支持,但这样做的方式仍然使消息与其他实现保持兼容。在推动下,也许我可以通过谷歌规范中的新扩展属性添加 protogen 支持,但我还没有这样做。

所以; 看例子;表示BaseMessage和之间的继承关系BeginRequest;无论您是否这样做:

Serialize<BaseMessage>(...)
Serialize<BeginRequest>(...)
  • 无论哪种方式,它将从底部 ( BaseMessage) 开始并向上工作;这并不完全正确 - 它以开头写入数据BeginRequest(以便它知道我们BeginRequest在反序列化期间尽早拥有 a )。重要的是包含来自任何父合约类型的字段,并且序列化程序会查看传入的实际对象 - 而不仅仅是您所说的类型。

同样,在反序列化期间,无论您是否使用:

Deserialize<BaseMessage>(...)
Deserialize<BeginRequest>(...)

你会得到你实际序列化的类型(大概是 a 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]

(在这种情况下,子消息的正文为空)

这覆盖它吗?

于 2009-06-11T23:30:59.617 回答