15

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

假设我的 .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;
      }
  } 

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

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

4

4 回答 4

14

正如 Marc Gravell 上面所说的 - 协议缓冲区不处理泛型或继承。

于 2012-09-25T00:18:06.253 回答
10

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

于 2014-12-22T07:42:20.557 回答
7

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

你使用包装类

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。

于 2015-12-15T14:20:13.350 回答
5

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

于 2019-01-08T11:10:12.613 回答