为什么在Java的Protocol Buffers和protobuf-net中序列化时byte[]是不同的?

3
当我在Java中使用协议缓冲区对该对象进行序列化时,我会得到以下字节数组:
byte[] topic = Transport.newBuilder()
            .setTopic(Topics.ORD)
            .setExtension(Ord.command, Commands.INSERT)
            .build()
            .toByteArray();

// [8,2,16,0]

当我使用protobuf-net做同样的事情时,我得到了以下结果。
var transport = new Transport
{
    topic = Topics.ORD,
    command = Commands.INSERT
};

var stream = new MemoryStream();
Serializer.Serialize(stream, transport);
byte[] result = stream.ToArray(); // [8,2]

在使用zmq以及基于字节数组的订阅时,这会给我带来一些麻烦。我该如何确保两个数组看起来是相同的?

1个回答

3
protobuf-net在v1版本中有一个"零默认值"的假设。如果我从头开始,可能不会做出这样的决定,在v2版本中可以禁用此行为。但是目前情况是,它在许多情况下都会将零作为隐含默认值。我猜想你的command是一个非空的枚举类型,在这种情况下,它将应用此逻辑(顺便提一句:如果它是可空的,它就不会这样做-它将使用null检查来进行包含/排除决策)。
因此,它已经决定了第二个字段(作为varint编码的字段号2)不需要序列化。因此没有[16,0]
选项:
  • 使用可空成员(相当于optional)-即public SomeEnum? Command {get;set;}
  • 将成员标记为必需的(在ProtoMemberAttribute上设置IsRequired=true
  • 关闭隐式零默认行为(对RuntimeTypeModel实例设置UseImplicitZeroDefaults

好的,我已经将proto文件中的字段设置为必需。现在在C#中我得到了[8,2,176,6,0],而在Java中则是[8,2,-80,6,0] - mrt181
2
@mrt181 这只是因为Java有带符号字节,而C#有无符号字节;176和-80是同一件事(二进制10110000)。 - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接