В protobuf-net можно частично десериализовать сообщение на основе базового типа - PullRequest
4 голосов
/ 15 февраля 2011

в protobuf-net можно ли частично десериализовать сообщение на основе базового типа?

В моей системе у меня есть иерархия наследования, где каждое сообщение наследуется от MessageBase. MessageBase имеет тип сообщения MessageType. В идеале я хочу только десериализовать MessageBase и проверить, интересует ли это MessageType, тогда я могу либо выбросить сообщение, либо принять решение о десериализации реального сообщения. Это позволяет сэкономить на десериализации (у меня есть бюджет цикла процессора и много сообщений для обработки).

Пример использования показан ниже.

Большое спасибо.

 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; }
    }
}

1 Ответ

3 голосов
/ 15 февраля 2011

Если это часть сообщения, то в данный момент: нет.Поскольку это поле 1, я мог бы потенциально предварительно просмотреть их, но даже это взлом (нет гарантии, что поле 1 будет первым - спецификация ясно дает понять, что вы должны разрешить любой порядок).

Однако!

может быть вариант, если вы открыты для небольшого рефакторинга.Если это линейная гетерогенная последовательность сообщений, то другой способ ее кодирования - использовать реализацию SerializeWithLengthPrefix, передавая разные теги для каждого типа сообщений - тогда у вас есть последовательность, подобная (будучи немного либеральной с представлением)

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

конечно, это немного зависит от сопоставления другого конца, но если я не ошибаюсь, это довольно хорошо связывается с SAX-подобной обработкой , обсуждаемой здесь (как предложение),что, кстати, также полностью совместимо с тем, как работает десериализация NonGeneric.Вот пример того, что only десериализует объекты 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 не станет ясной, поскольку пока она выглядит как точное соответствие моей реализации.Что приятно.

...