事先原谅任何关于protobuffers或Go的无知,因为这两种技术对我来说都比较新。
我们已经在生产中使用protobuffers和protobuf-net一段时间了。我们使用Redis作为系统之间的消息队列,读取或写入Redis的所有内容都使用完全相同的模型(共享库)和protobuf-net来序列化和反序列化。但是,现在我们想要用Go编写的系统将内容推送到Redis中。我的问题是,使用protobuf-net在我的.NET应用程序中无法对Go编写的protobuffer数据进行反序列化
针对我的问题,请参阅以下小例子。
我正在使用protoc版本2.6.1用于Golang方法和protobuf-net版本2.0.0.668用于.NET
[ProtoContract]
[ProtoInclude(3, typeof(SomeDerivedClass))]
public abstract class BaseClass
{
[ProtoMember(1)]
public Int32 Foo { get; set; }
}
[ProtoContract]
public class SomeDerivedClass : BaseClass
{
[ProtoMember(2)]
public String Bar { get; set; }
}
使用Serializer.GetProto<SomeDerivedClass>();
会生成以下.proto文件:
message BaseClass {
optional int32 Foo = 1 [default = 0];
// the following represent sub-types; at most 1 should have a value
optional SomeDerivedClass SomeDerivedClass = 3;
}
message SomeDerivedClass {
optional string Bar = 2;
}
使用protogen,产生以下.go文件: https://gist.github.com/cjqed/408dd9fd11e935239f36
然后,
derived := &SomeDerivedClass{
Bar: proto.String("h"),
}
baseClass := &BaseClass{
SomeDerivedClass: derived,
Foo: proto.Int32(13),
}
data, err := proto.Marshal(baseClass)
if err != nil {
panic(err)
}
使用protobuf-net反序列化时,会产生
结果:ProtoException, No parameterless constructor found for BaseClass
......除非我使BaseClass非抽象。虽然可能,但这并不是一个很好的解决方案。
最后,我在protobuf-net和Go中创建了完全相同的对象(两者都在同一台机器上,请注意),这些是每个的字节:
(protobuf-net中的代码序列化)
var obj = new SomeDerivedClass
{
Bar = "h",
Foo = 13
};
byte[] data;
using (var memoryStream = new MemoryStream())
{
Serializer.Serialize(memoryStream, obj);
data = memoryStream.ToArray();
}
protobuf网:
26, 3, 18, 1, 104, 8, 13
使用github.com/golang/protobuf/proto:
8, 13, 26, 3, 18, 1, 104
注意protobuf-net中的最后两个字节是golang中的前两个字节。
那么,我做错了什么,或者两个protobuffer库中有一个错误?或者也许是去生素?