如何在 .proto 文件中处理带有协议缓冲区的通用类型对象?

问题描述 投票:0回答:5

我花了一些时间寻找一些替代方法来处理通用对象,我看到了与我类似的问题,但没有我想的那么具体? 协议缓冲区有多种我可以使用的标量类型,但它们大多是原始的。 我希望我的消息灵活并且能够有一个作为某种列表的字段。

假设我的 .proto 文件如下所示:

   message SomeMessage
   {
      string datetime = 1;
      message inputData // This would be a list
      {
         repeated Object object = 1;
      }
      message Object 
      {
          ? // this need to be of a generic type - This is my question
          // My work around - Using extentions with some Object
          //List all primitive scalar types as optional and create an extension 100 to    max;
      }
      message someObject //some random entity - for example, employee/company etc.
      {  
          optional string name = 1; optional int32 id = 2;
      }
      extend Object 
      {
          optional someObject obj = 101;
      }
  } 

这很好,并且可以工作,并且我有一个列表,其中对象可以是任何原始类型,也可以是列表< someObject >。 然而,这里的问题是,任何时候我需要处理新类型的对象,我都需要编辑我的 .proto 文件,重新编译 C# 和 java(我需要它的语言)...

如果协议缓冲区无法处理通用对象类型,是否有其他替代方案可以? 非常感谢有关此事的任何帮助。

object protocol-buffers generic-list
5个回答
20
投票

正如 Marc Gravell 上面所说 - Protocol Buffers 不处理泛型或继承。


13
投票

虽然我迟到了,只是为了新观众, 您可以使用字节代替对象,并且可以是您可以序列化/反序列化的任何对象。


10
投票

这是 Structprotobuf 3 定义,它基本上使用

oneof
来定义此类“通用”消息类型。


8
投票

可以实现通用消息功能,但添加新类型仍然需要重建原型类。

您使用包装类

message Wrapper {
    extensions 1000 to max;
    required uint32 type = 1;
}

然后添加一些类型

message Foo {
    extend Wrapper {
        optional Foo item = 1000;
    }

    optional int attr1_of_foo = 1;
    optional int attr2_of_foo = 2;
    optional int attr3_of_foo = 3;
}

message Bar {
    extend Wrapper {
        optional Bar item = 1001;
    }

    optional int attr1_of_bar = 1;
    optional int attr2_of_bar = 2;
    optional int attr3_of_bar = 3;
}

看看我们如何使用扩展在我们想要由 Wrapper 类存储的类中扩展 Wrapper 类。

现在,创建 Foo 包装对象的示例。我使用Python,因为它是最简洁的形式。其他语言也可以这样做。

wrapper = Wrapper()
wrapper.type = Foo.ITEM_FIELD_NUMBER
foo = wrapper.Extensions[Foo.item]
foo.attr1_of_foo = 1
foo.attr2_of_foo = 2
foo.attr3_of_foo = 3
data = wrapper.SerializeToString()

以及反序列化的示例

wrapper = Wrapper()
wrapper.ParseFromString(data)
if wrapper.type == Foo.ITEM_FIELD_NUMBER:
    foo = wrapper.Extensions[Foo.item]
elif wrapper.type == Bar.ITEM_FIELD_NUMBER:
    bar = wrapper.Extensions[Bar.item]
else:
    raise Exception('Unrecognized wrapped type: %s' % wrapper.type)

现在,因为您想要通用集合,请将 Wrapper 设为其他消息的重复字段,然后瞧。

当然这不是完整的解决方案,这个架构需要更多的封装才能使其易于使用。有关更多信息,请阅读有关 Protobuf 扩展的信息,尤其是嵌套扩展 (https://developers.google.com/protocol-buffers/docs/proto#nested) 或 google 有关项目编组的信息。


0
投票

如果 java 需要,这一步不只是为了正确的文档目的,因为在 PyObject 包装器上执行 call 能够将参数传递给对象本身(?)

© www.soinside.com 2019 - 2024. All rights reserved.