2015-04-02 47 views
2

我想通过protobuf-net向单个通道发送混合消息类型。我将来自各种来源的以下示例放在一起,并在第一次反序列化时引发StackOverflow异常。Protobuf-net StackOverflow异常与派生类型

我对此有何看法?

FWIW它创建的文件的十六进制内容是 “A2 06 02 08 02 08 01 AA 06 02 08 04 08 03”

谢谢,格雷格

[ProtoContract(ImplicitFields = ImplicitFields.AllFields)] 
[ProtoInclude(100, typeof(Derived1))] 
[ProtoInclude(101, typeof(Derived2))] 
public class Base { public int Old; } 

[ProtoContract(ImplicitFields = ImplicitFields.AllFields)] 
public class Derived1 : Base { public int New1; } 
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)] 
public class Derived2 : Base { public int New2; } 

class Program 
{ 
    static void Main(string[] args) 
    { 

     Base b1 = new Derived1() { Old = 1, New1 = 2 }; 
     Base b2 = new Derived2() { Old = 3, New2 = 4 }; 

     using (var fs = File.Create(@"C:\test.bin")) 
     { 
      Serializer.Serialize(fs, b1); 
      Serializer.Serialize(fs, b2); 
     } 

     Base msg3, msg4; 
     using (var fs = File.OpenRead(@"C:\test.bin")) 
     { 
      msg3 = Serializer.Deserialize<Base>(fs); 
      msg4 = Serializer.Deserialize<Base>(fs); 
     } 

     Console.WriteLine(((Derived1)msg3).New1); 
     Console.WriteLine(((Derived2)msg4).New2); 
     Console.ReadLine(); 
    } 
} 

回答

2

我希望这里的问题是framing; protobuf(格式,而不是库)是由谷歌设计的可追加,其中追加===合并。如果序列化消息A,则立即序列化消息B,然后反序列化整个批次:获得一个消息,而不是两个。这显然有很大的潜力,导致意想不到的结果,错误地解释数据和错误。

然后,诀窍是将消息框起来,以便可以分别处理它们。幸运的是,protobuf-net为此提供了SerializeWithLengthPrefixDeserializeWithLengthPrefix方法。在序列化过程中,这会在每条消息的前面添加一个标记以指示随后的数据长度。在反序列化期间,首先读取长度前缀,从而允许为每条消息使用正确数量的数据。

支持多种布局和长度前缀样式;最重要的是他们匹配之间的序列化和反序列化步骤。如果你希望数据是“纯粹的protobuf”(即可解析为另一个平台上的外部消息上的repeated字段),那么“base-128,field 1”是一个不错的选择。

这工作得很好:

using (var fs = File.Create(@"test.bin")) 
{ 
    Serializer.SerializeWithLengthPrefix(fs, b1, PrefixStyle.Base128, 1); 
    Serializer.SerializeWithLengthPrefix(fs, b2, PrefixStyle.Base128, 1); 
} 

Base msg3, msg4; 
using (var fs = File.OpenRead(@"test.bin")) 
{ 
    msg3 = Serializer.DeserializeWithLengthPrefix<Base>(fs, PrefixStyle.Base128, 1); 
    msg4 = Serializer.DeserializeWithLengthPrefix<Base>(fs, PrefixStyle.Base128, 1); 
} 
+0

非常感谢你,是没有的伎俩! – 2015-04-03 14:58:17