我们在.NET中有一些(很多)类 . 我们使用protobuf-net标记它们,并通过google original library生成C代码侧的.proto包装器 .
所以我在一些EventBase类上有一条消息(C DebugString()(在.NET EventCharacterMoved
中继承 EventBase
,而在C中我只是写入可选属性)):
UserId: -2792
EventCharacterMoved {
Coordinates {
Position {
X: 196.41913
Y: 130
Z: 213
}
Rotation {
X: 207
Y: 130
Z: 213
}
}
OldCoordinates {
Position {
X: 196.41913
Y: 130
Z: 213
}
Rotation {
X: 207
Y: 130
Z: 213
}
}
}
(来自这样的.proto文件)
message Coordinates {
optional TreeFloat Position = 1;
optional TreeFloat Rotation = 2;
}
message EventBase {
optional int32 UserId = 10 [default = 0];
// the following represent sub-types; at most 1 should have a value
optional EventCharacterMoved EventCharacterMoved = 15;
}
message EventCharacterMoved {
optional Coordinates Coordinates = 100;
optional Coordinates OldCoordinates = 101;
}
message TreeFloat {
optional float X = 1 [default = 0];
optional float Y = 2 [default = 0];
optional float Z = 3 [default = 0];
}
在C中我发送这个,我们从.NET发送相同的消息内容 .
C代码可以解析C编码的消息以及.NET编码的消息 . .NET代码只能解析.NET消息 .
在线上我们得到87个字节飞行(相同大小来自.Net file和C++ file)但内容不同:
你可以看到它的相似但不一样 . 由于这种差异 CPP code can read .NET C# messages while .NET can not read CPP messages .
在反序列化的代码中,我们得到:
TestProto.exe中出现未处理的“System.InvalidCastException”类型异常附加信息:无法将类型为“TestProto.EventBase”的对象强制转换为“TestProto.EventCharacterMoved” .
在代码中:
using (var inputStream = File.Open(@"./cpp_in.bin", FileMode.Open, FileAccess.Read)) {
var ecm = Serializer.Deserialize<EventCharacterMoved>(inputStream);
}
让我们看一下(如他的评论中的jpa所述) protoc --decode_raw
选项:
这可能与我的CPP包装使用最新的google protobuf版本有关,而protobuf-net可能使用一些较旧的编码格式或类似的东西......
所以我想知道如何使.NET protobuf读取C消息(使tham能够解码相同的东西)?
或者至少如何使原始谷歌protobuf编码与.NET protobuf相同?
对于那些真正感兴趣并想进入它的人zipped bundle with simplified example (VS 2010 solutions for C++ and C# code included)
2 回答
编辑;这应该在r616及以上版本中修复 .
我终于有机会看到这一点(对延迟道歉,但社会季节性假期要求介入) . 我明白现在发生了什么 .
基本上,数据在理论上是相同的;实际上归结为字段排序 . 从技术上讲,字段通常按升序编写,但可以按任何顺序预期 . 关于protobuf-net;对于不涉及继承的类型,无论顺序如何,它都可以正常工作 . protobuf规范没有定义继承,因此protobuf-net除了规范之外还增加了对它的支持(由于需求不断) . 作为实现特征,它首先写入子类信息(即,字段15,子类型,在字段10之前写入) . 在当前,在反序列化期间,它还首先期望子类型信息 . 这很少影响任何人,因为protobuf-net是唯一使用这种继承的实现,所以继承功能的使用大多只能用于protobuf-net到protobuf-net的使用 .
在您的情况下,您使用.proto与CPP互操作;这意味着CPP代码将能够使用protobuf-net数据,但它可能有另一种方式的类型转换异常(基本上,它在获取第一个数据字段时开始构建具体类型) .
尽管很少出现问题,但这是需要修复的问题 . 我可以在今天或明天晚些时候试着看一下 .
选项:
确保子类型字段始终低于任何数据字段
如果您知道它需要子类型,请使用Merge API并传入所需类型的现有新对象 - 这将正确填充现有对象
等一两天(希望!)使用build r616或更高版本进行正确修复
使用互操作时避免继承(以及其他特定于实现的功能)
请注意,您可以通过封装对没有继承的相同数据进行建模 - 并且它可以很愉快地工作;特别是具体类型的创建是这里的问题
在从CPP站点构造数据时,通过将其写成两部分来达到不合理的长度(意思是:我不认为这是一个实际的解决方案):
首先用
EventCharacterMoved
EventCharacterMoved
写一个EventBase
,并序列化;现在在一个单独的模型中写一个EventBase
与 just 的TreeFloat
数据,并序列化;这将模拟以所需顺序编写它们(protobuf流是可附加的) - 不漂亮这看起来非常类似于http://code.google.com/p/protobuf-net/issues/detail?id=299和http://code.google.com/p/protobuf-net/issues/detail?id=331中提到的问题,据称这些问题由http://code.google.com/p/protobuf-net/source/detail?r=595修复
.NET protobuf的版本是否已经足够新用于合并该修复程序?