Subtype fieldnumber order dependent in protobuf-net

北城以北 提交于 2021-02-07 08:52:00

问题


I can see that protobuf-net seems to need to have deterministic ordering on the run type model. What's a good strategy to use without the need of having attributes on each class for the ordering.

How does protobuf it self do if it were that you were implementing by attributes instead ?

model.Add(typeof(IMessage), false).AddSubType(8500, typeof(DogBarkedEvent));
model.Add(typeof(IMessage), false).AddSubType(8501, typeof(DogBarkedEvent2));

if I create a new model and try to deserialize with

model2.Add(typeof(IMessage), false).AddSubType(8655, typeof(DogBarkedEvent));
model2.Add(typeof(IMessage), false).AddSubType(5300, typeof(DogBarkedEvent2));

it sure fails.

I do not know how many subtypes there will be at runtime, thats why i have a concern that the order may change next time an application is launched.

I've read this previous post protobuf-net v2 type meta it though doesnt say how the a good approach regarding the UniqueIdentifier is generated.


回答1:


It isn't order dependent - it is value dependent. prototobuf (meaning: the specification defined by google; not protobuf-net specifically) is very terse. All you get on the wire is numeric identifiers telling you what you are about to get.

If we consider properties/fields first (.Name, .DateOfBirth, etc) - then this is how it maps between (say) the key 17 on the wire, and the .Name property. Obviously if you store the data when Name <===> 17, and then change your mind, and read it back when Name <===> 22 and ShoeSize <===> 17, then there are going to be huge problems. The field-number mapping is an essential part of the contract; you should not change the field-number mapping if you need to read old data (well, there are some limited ways around it involving custom models and a few tricks... but nothing fun).

Now; let's consider inheritance. protobuf does not define inheritance; in any way. For your convenience, protobuf-net provides a mechanism to make inheritance work, by modelling inheritance as encapsulation of sub-objects. This means that mapping DogBarkedEvent <===> 8500 is fundamentally no different to our Name / ShoeSize example later. If we change our mind and use a different field-number, it will fail.

So yes, you need a robust repeatable way of generating the same key for DogBarkedEvent every time, regardless of how many other sub-classes have been added / removed / renamed. The easiest way is to use the attributes such as [ProtoInclude(...)], because that is then fixed and static in the code. If that is not desirable, then some kind of external storage of the map would be recommended; a flat text file would do - just parse it and apply; i.e.

My.NameSpace.DogBarkedEvent=8500
My.NameSpace.DogBarkedEvent2=8501

It also depends on why you don't want to use [ProtoInclude(...)]; if this is because your code file is generated, then consider partial classes:

namespace My.NameSpace
{    
    [ProtoInclude(8500, typeof(DogBarkedEvent))]
    [ProtoInclude(8501, typeof(DogBarkedEvent2))]
    partial class MyParentType {}
}

If the issue is that you don't want to use library-specific types in the code; then maybe declare your own attribute and read that when configuring the model; for example:

[SubtypeKey(8500, typeof(DogBarkedEvent))]
[SubtypeKey(8501, typeof(DogBarkedEvent2))]

(and fetch with Attribute.GetCustomAttribute)



来源:https://stackoverflow.com/questions/15332380/subtype-fieldnumber-order-dependent-in-protobuf-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!