2011-02-15 45 views
4

protobuf-net是否可以根據基類型部分反序列化消息?在protobuf-net中是否有可能部分反序列化一個基於基類型的消息

在我的系統中,我有一個繼承層次,其中每個消息都從MessageBase繼承。 MessageBase有一個uint MessageType。理想情況下,我只想反序列化MessageBase並檢查它是否是我感興趣的MessageType,然後我可以丟棄該消息或作出反序列化實際消息的決定。這是爲了節省反序列化的成本(我有一個CPU週期預算和大量的消息處理)。

示例用法如下所示。

非常感謝。

MessageBase msgBase = ..deserialize; 

    if(msgBase.MessageType = 1)//1 is the Tick msg type 
    { 
    Tick tick = ..deserialize actual msg; 
    //do something with tick 
    } 
    //throw away msgBase 

[ProtoContract,ProtoInclude(1, typeof(Tick))] 
public class MessageBase 
{ 
    protected uint _messageType; 

    [ProtoMember(1)] 
    public uint MessageType 
    { 
     get { return _messageType; } 
     set{ _messageType = value;} 
    } 
} 

[ProtoContract] 
public public class Tick : MessageBase 
{ 
    private int _tickId; 
    private double _value; 

    public Tick() 
    { 
     _messageType = 1; 
    } 

    [ProtoMember(1)] 
    public int TickID 
    { 
     get { return _tickId; } 
     set { _tickId = value; } 
    } 
    [ProtoMember(2)] 
    public double Value 
    { 
     get { return _value; } 
     set { _value = value; } 
    } 
} 

回答

3

如果它是消息的部分,然後在時刻:沒有。由於它是字段1,我可以潛在預先篩選它們,但即使這是一個黑客(不保證字段1是第一個 - 規範明確表示您必須允許任何排序)。

但是!

如果您打算進行一些重構,可能會有一個選項。如果這是一個線性異構消息序列,那麼對其進行編碼的另一種方法是使用SerializeWithLengthPrefix實現,爲每種消息類型傳遞一個不同的標籤 - 然後您將得到一個類似的序列(對於該表示有點自由)

1:[tick-body] 2:[some-other-body] 1:[tick body] etc 

當然這取決於在另一端匹配,但除非我誤認爲這與SAX類似的處理discussed here(作爲提議)相關,這偶然地也完全兼容NonGeneric反序列化作品。下面是一個例子,即反序列化Bar目的,示出了「2」和「4」在控制檯上:

using System; 
using System.IO; 
using ProtoBuf; 
[ProtoContract] 
class Foo 
{ 
    [ProtoMember(1)] 
    public int A { get; set; } 
} 
[ProtoContract] 
class Bar 
{ 
    [ProtoMember(1)] 
    public int B { get; set; } 
} 
static class Program 
{ 
    static void Main() 
    { 
     using (var ms = new MemoryStream()) 
     { 
      Serializer.SerializeWithLengthPrefix(ms, new Foo { A = 1 }, PrefixStyle.Base128, 1); 
      Serializer.SerializeWithLengthPrefix(ms, new Bar { B = 2 }, PrefixStyle.Base128, 2); 
      Serializer.SerializeWithLengthPrefix(ms, new Foo { A = 3 }, PrefixStyle.Base128, 1); 
      Serializer.SerializeWithLengthPrefix(ms, new Bar { B = 4 }, PrefixStyle.Base128, 2); 
      ms.Position = 0; 

      // we want all the Bar - so we'll use a callback that says "Bar" for 2, else null (skip) 
      object obj; 
      while (Serializer.NonGeneric.TryDeserializeWithLengthPrefix(ms, PrefixStyle.Base128, 
       tag => tag == 2 ? typeof(Bar) : null, out obj)) 
      { 
       Console.WriteLine(((Bar)obj).B); 
      } 
     } 
    } 
} 

在導線,這是與父對象實際上兼容:

repeated foo foo = 1; 
repeated bar bar = 2; 

如果建議的option generate_visitors得到實施,您應該能夠從任何客戶端使用相同類型的異構數據流。明顯的映射就像[ProtoContract]上的一個可選屬性 - 但我不想補充說明,直到新的protobuf功能清楚爲止,因爲目前爲止它看起來與我的實現完全匹配。這很好。

+0

謝謝我將使用您的示例代碼。 – DayTwo 2011-02-15 12:16:29

相關問題