ProtoInclude 属性是什么意思(在 protobuf-net 中)

发布于 2024-07-22 21:29:46 字数 745 浏览 6 评论 0原文

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

举个例子将不胜感激。

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

[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 工具生成这样的继承?

In the ProtoBuf-Net implementation, what does the ProtoInclude attribute mean, and what does it do?

An example would be appreciated.

I saw it in this post and I'm not sure what it does. The example was:

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

Also, is there a way to generate such inheritance using the protogen tool?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

动次打次papapa 2024-07-29 21:29:48

抱歉,我不是故意错过这个的 - 唉,我没有看到全部。

考虑到问题中的具体细节,我假设您至少对 .proto 有点熟悉; 如果我错了请纠正我。

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

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

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

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]< /code>,顺便说一句,

通常,它会按升序标记顺序写入字段,但为了实现高效的反序列化,引擎厚颜无耻地选择首先写入子类数据(这是规范明确允许的) -即它写了类似的内容(您必须想象二进制文件...):(

[tag 50, string][length of sub-message][body of sub-message][tag 1, int][value]

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

这是否涵盖了它?

Sorry, I didn't mean to miss this one - alas, I don't see everything.

Given the specifics in the question, I'm going to assume that you are at least passingly familiar with .proto; correct me if I am wrong.

[ProtoInclude] works a lot like [XmlInclude] for XmlSerializer - or [KnownType] for DataContractSerializer - it allows it to recognise subclasses of a type during (de)serialization. The only additional thing is that it needs a tag (number) to identify each sub-type (that must be unique, and not clash with any of the fields from the parent type).

Re protogen: nope; the underlying spec (by google) makes no provision for inheritance at all, so protogen (via .proto) has no mechanism to express this. protobuf-net provides inheritance support as an extension, but does it in a way that still leaves the messages wire-compatible with the other implementations. At a push, maybe I could add protogen support via the new extension properties in the google spec, but I haven't done this yet.

So; to look at the example; that expresses an inheritance relationship between BaseMessage and BeginRequest; regardless of whether you do:

Serialize<BaseMessage>(...)
Serialize<BeginRequest>(...)
  • either way, it will start at the base (BaseMessage) and work upwards; which isn't exactly true - it writes the data starting with BeginRequest (so that it knows we have a BeginRequest as early as possible during deserialization). The important thing is that the fields from any parent contract types is included, and the serializer looks at the actual object passed in - not just the type you say it is.

Likewise, during deserilaization, regardless of whether you use:

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

you will get the type you actually serialized (presumably a BeginRequest).

Under the bonnet, for compatibility purposes (with the wide protocol buffers specification), this is similar to writing something like (forgive any errors, my .proto is rusty):

message BaseMessage {
    optional BeginRequest beginRequest = 50;
    optional uint32 messageType = 1;   
}
message BeginRequest {        
}

(the override probably shouldn't specify [ProtoMember], btw.

Normally, it would write fields in ascending tag order, but to make for efficient deserialization the engine cheekily chooses to write the subclass data first (which is explicitly allowed by the spec) - i.e. it writes something like (you'll have to imagine the binary...):

[tag 50, string][length of sub-message][body of sub-message][tag 1, int][value]

(in this case, the body of the sub-message is empty)

Does that cover it?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文