问题
It was mentioned here that protobuf-net can be used like a SAX parser, but I couldn't find examples for this that did not require a more or less complete description of the object to parse.
(Skip to point 2) for the question, 1) just provides some context)
1) Perhaps I should provide some context first:
I am currently using JSON.Net in my project and have created several JSONConverters to customize how various types are serialized – basically all major types have hand-written serialization instructions (ReadProperty, ReadValue, etc.).
Some examples why and where I did this:
- I have a
MetaType
class that describes how certainValue
objects behave at runtime. TheseValue
objects have aType
property that is serialized. A Converter returns only the name of theMetaType
when serializing this property and uses the name to obtain the correspondinfMetaType
when de-serializing. The reason for this is that the name of the type is enough, theMetaType
class is too cumbersome to serialize and the resulting JSON is more compact. - Several objects have collections that contain values that need not be serialized, because I can re-create them based on the
MetaType
when they are not present. A Converter filters these collections and stores only those value that are not default values – while JSON.Net has attributes that prevent properties from being serialized when they are set to default values, I do not know of any built-in ways to filter default values from a collection.
What is my goal:
Since I already have so much handwritten seralization code, I want to get rid of the OR-Mapper. The reason for this is that I can more easily create migrators that can read old JSON formats and perform necessary migration steps (add data, ignore no longer needed data, etc.). With an OR-Mapper, I need the old types to parse old formats and then convert the old types to new types – which is a valid strategy, but because I have the handwritten code, I can perform very fine granular migration steps and react to pretty much any change. Basically more power and I don't need the old object model.
2) So what's the actual question?
Can I use protobuf-net to more or less manually read/write data from/to a stream OR have similar power over the (de-)serialization in some other way (e.g. RuntimeTypeModel? )
To use the examples from above:
- I have an object with a property of type
MetaType
, but instead of serializing the wholeMetaType
, I only want to store a string or ID. When de-serializing, the string or ID is used to obtain the correctMetaType
(<= I only need the parser to store / read the ID, I'll do the lookup) - I want to be able to filter collections on serialization and only store objects that meet certain criteria.
- I want to be able to support old formats by being able to read them and migrate the data as necessary. I already store a version number that can be used to either branch the de-serialization or create different types of objects (v1, v2) – though I'd prefer it if I need not have to use multiple versions of my object model, migrating at parser level (before objects are created) would be great.
A pseudo code example (in case the above makes no sense):
int version = Reader.ReadInt()
// [...] decide how to proceed based on version
var typeName = Reader.ReadString()
var type = MetaType.For(typeName)
// [...] read some more properties
return new ValueObject(type, property1, property2)
Is something similar possible / recommended with protobuf-net? (Examples / Links to Documentation or Tutorials would be great – I know there's a ProtoReader class, but I'm not sure if I'm supposed to use that / if I'm smart enough to work with it without any docs)
Edit:
Adding Marc's comment here for better visibility:
An example of the raw usage of ProtoReader
/ ProtoWriter
can be found here (direct link to code).
回答1:
Most of that is possible. At the rawest level, ProtoReader has a full API for reading the underlying stream. If you know you just want to read "field 1 as an intended" (for the version etc) you can set up a model with just that and get the library to do the heavy lifting:
[ProtoContract] class VersionStub {
[ProtoMember(1)] public int Version {get;set;}
}
If you have multiple incompatible versions of the same model, different RuntimeTypeModel instances can be created and used separately (you should still cache and reuse the model where possible for performance).
However, the API is based around pre-existing concrete types - it allows you to configure the map at runtime but it does not currently create DTO types on the fly. It could. Though - it has more than enough inbuilt meta-programming already...
Did I answer the question? Or a different one?
来源:https://stackoverflow.com/questions/15095991/can-i-use-protobuf-net-as-a-sax-like-parser-without-a-full-type-definition