2015-04-02 98 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