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

ryv*_*ron 6 object generic-list protocol-buffers

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

假设我的.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;
      }
  } 
Run Code Online (Sandbox Code Playgroud)

这样就可以了,并且可以工作,并且我有一个List,其中Objects可以是任何原始类型,也可以是List <someObject>.但是 - 这里的问题是,每当我需要处理一种新类型的对象时,我需要编辑我的.proto文件,重新编译C#和java(我需要它的语言)...

如果协议缓冲区无法处理通用对象类型,那么还有另一种选择吗?非常感谢任何有关此事的帮助.

ryv*_*ron 9

正如Marc Gravell所述 - Protocol Buffers不处理泛型或继承.


Ama*_*war 9

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


Jul*_*rra 9

这是Protobuf 3 对 Struct 的定义,它基本上用于oneof定义此类“通用”消息类型。


omi*_*ron 5

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

您使用包装类

message Wrapper {
    extensions 1000 to max;
    required uint32 type = 1;
}
Run Code Online (Sandbox Code Playgroud)

然后添加一些类型

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;
}
Run Code Online (Sandbox Code Playgroud)

看看我们如何在我们希望由 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()
Run Code Online (Sandbox Code Playgroud)

和反序列化的例子

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)
Run Code Online (Sandbox Code Playgroud)

现在,因为你想要泛型集合,所以让 Wrapper 成为其他消息的重复字段,瞧。

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