protobuf-net v2 type meta

2019-01-24 20:08发布

问题:

According to this post (from March), protobuf v2 allows us to resolve types from a stream. Since v2 is now in beta 5, I think this feature has already been implemented, so I was wondering how to use this new feature. I haven't been able to find any documentation on it, so some help would be greatly appreciated !

Type meta

The serialization is fine, but I don’t know (and cannot know) all of my types up front. How can I do this?

Well, protobuf is a contract based format; if you don’t know the types, it will struggle – as will any contract based serializer…

Yes, I get that; now: how do I do it?

Now, I’ve held off putting any meta in the stream for various reasons:

it steps far outside the core protobuf spec it flashes the warning signs of BinaryFormatter, my nemesis But, so many people seem to want this that I think I have to buckle; but on my terms! So in v2, I’m adding the ability to indicate that (on a per-member basis) objects should resolve their type information from the stream. By default, by embedding the assembly-qualified-name, but providing an abstraction layer over that allowing you to provide your own string<===>Type map (and thus avoiding the knots in by stomach caused by too much type dependency).

回答1:

The trick here is to use the DynamicType = true option on a member to your object - as an over-simplified example:

[ProtoMember(12, DynamicType = true)]
public object CouldBeAnything {get;set;}

Re the "string<===>Type map", that is the DynamicTypeFormatting event on TypeModel. If you are using the Serializer.* methods, that is a shortcut (mainly for preserving the v1 API) to the RuntimeTypeModel.Default serializer instance.

(as a side-note, in writing this I did notice an edge-case that I need to go and fix in the code)

Note: another approach here, rather than using DynamicType, is to simply configure the model at runtime, for example:

var knownTypes = GetMyKnownTypesAtRuntimeWithUniqueIdentifiers();
var metaType = typeModel[typeof(MyBaseClass)];
foreach(var knownType in knownTypes)
{
    metaType.AddSubType(knownType.UniqueIdentifier, knownType.Type);
}

IMO this latter is my preferred option, and will generally be more efficient. Note that it is necessary for the unique-identifiers to be fixed/repeatable, as that is part of the wire format (don't just use the index of the order you find them).