In protobuf-net, you can partially deserialize a message based on a base type

in protobuf-net can partially deserialize a message based on the base type?

On my system, I have an inheritance hierarchy where every message is inherited from MessageBase. MessageBase has a uint MessageType. Ideally, I just want to deserialize the MessageBase and see if MessageType Im is interested in it, then I can either throw the message away or decide to deserialize the actual message. This is necessary to save the cost of deserialization (I have a processor cycle budget and a lot of messages to process).

Usage example shown below.

Thank you very much.

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; } } } 
+4
source share
1 answer

If this is part of the message, then at the moment: no. Since this field is 1, I could preview them, but even hack them (there is no guarantee that the first field - the specification makes it clear that you must allow any ordering).

But!

It may be an option if you are open to small refactoring. If this is a linear heterogeneous message sequence, then another way of encoding it is to use the implementation of SerializeWithLengthPrefix , passing a different tag for each type of message - then you have such a sequence (which is a bit liberal with presentation)

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

of course, it depends a little on a different match, but if I’m not mistaken, these connections go quite well with the SAX-like processing discussed here (as a suggestion), which, by the way, is also fully compatible with how Deserialize NonGeneric works. Here is an example that only deserializes Bar objects by displaying "2" and "4" on the console:

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

On wiring, this is actually compatible with the parent:

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

If the proposed option generate_visitors is implemented, you can use the same type of heterogeneous data stream from any client. An obvious comparison would be a bit of an optional property on [ProtoContract] to help with this, but I don't want to add this until the new protobuf function becomes clear, as long as it looks like it exactly matches my implementation. Which is nice.

+3
source

Source: https://habr.com/ru/post/1339800/


All Articles