c# - 在 protobuf-net 中,是否可以部分反序列化基于基本类型的消息

标签 c# protocol-buffers 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; }
    }
}

最佳答案

如果它是消息的一部分,那么目前:不。由于它是字段 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 功能明确之前添加它,到目前为止它看起来与我的实现完全匹配。这很好。

关于c# - 在 protobuf-net 中,是否可以部分反序列化基于基本类型的消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5002216/

相关文章:

c# - 使用MySqlDataReader时遇到 fatal error

c# - 在 C# 中使用 DllImport 的最佳方法以及如何从外部方法取回控制权

protocol-buffers - 如何将 OpenAPI 规范 (Swagger 2.0) 转换为 proto3?

c# - Protobuf-net序列化/反序列化

c# - 我可以反序列化为 protobuf-net 中接口(interface)的只读属性吗?

c# - Chrome 字体不加载本地字体

c# - 如何使用grpc通过服务器在客户端之间发送消息?

c++ - 子目录中带有 protobuf 文件的 CMake

c# - 我如何使用 PrefixStyle 和 ProtoBuf-net 获取长度数?

c# - 检测 selenium webdriver 何时更改浏览器中的 url