Day*_*Two 5 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; }
}
}
Run Code Online (Sandbox Code Playgroud)
如果它是消息的一部分,那么目前:不。由于它是字段 1,我可能会预先筛选它们,但即使这样也是一种黑客行为(不能保证字段 1 是第一个 - 规范明确指出您必须允许任何排序)。
然而!
如果您愿意进行一些重构,那么可能有一个选择。如果这是消息的线性异构序列,那么对其进行编码的另一种方法是使用实现SerializeWithLengthPrefix,为每种消息类型传递不同的标签 - 那么您将得到一个类似的序列(对表示有点自由)
1:[tick-body] 2:[some-other-body] 1:[tick body] etc
Run Code Online (Sandbox Code Playgroud)
当然,这在一定程度上取决于另一端的匹配,但除非我弄错了,否则这与这里讨论的类似 SAX 的处理(作为提案)有很好的联系,顺便说一句,它也与 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);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在线路上,这实际上与父对象兼容:
repeated foo foo = 1;
repeated bar bar = 2;
Run Code Online (Sandbox Code Playgroud)
如果建议option generate_visitors得到实施,您应该能够从任何客户端使用相同类型的异构数据流。明显的映射就像是一个可选属性来[ProtoContract]帮助解决这个问题 - 但在新的 protobuf 功能明确之前我不想添加它,因为到目前为止它看起来与我的实现完全匹配。这很好。