Reposted here at the recommendation of Alexei Levenkov after the original question on the main stackoverflow site was marked as off-topic.
In .NET there are several different methods to serialize data. You've got:
- BinaryFormatter. Efficient, but any change to your data structure makes data saved in a previous version unreadable. Non-human readable format makes data hard to recover if anything goes wrong.
- XmlSerializer. Doesn't support references.
- DataContractSerializer. Supports references, but is rather finicky when it comes to data versioning. Adding properties is fine, for instance, but introducing a new base class for an existing class and moving some of its properties there changes the order in which they are serialized, which causes an error during deserialization unless you first manually reorder the xml in a pre-processing step, which is less than ideal.
- Adding a serialize and deserialize function to each class in which the order of the properties is explicitly defined and any necessary steps to convert data from one version to the next can be taken. This works, but is tedious to write.
- Protobuf-net. Requires annotating each property with an index. Non-human readable format makes data hard to recover if anything goes wrong.
- JSON.NET. Might be an option, but from what I'm able to gather writing converters involves modifying the json tree, whereas I would prefer to deserialize it as the old type first and then convert it to the new type in C# code, which provides type checking and an easier way to deal with references.
For the past three years or so I've been using a DataContractSerializer in the application I'm working on, but its inflexibilities have made refactoring the data structure more of a hassle than I'd like. Since I'm about to make a big change to the data structure, I figured this would be a good time to see if there were any better solutions regarding serialization.
Support for data versioning. Specifically this includes, but is not limited to, any of the following actions:
- Renaming classes
- Giving a class a base class
- Adding properties that have a default value that does not depend on other data
- Adding properties for which the default value depends on existing data
- Renaming properties
- Changing a property's type
- Reordering properties
- Moving properties to a base class
- Deleting properties
In general, there needs to be a way of defining how a new instance can be constructed from old data
- Preserving references. References should be preserved even if the referenced object needs to be upgraded to the new version (which potentially means it becomes a different class altogether)
- As little code overhead as possible, i.e. no explictly defining the order in which properties should be serialized. Ideally you should only need to specify how breaking changes, such as renaming a class or changing a property's type, should be resolved. Simple stuff like adding a property with a default value independent of the rest of the data or moving a property to a base class should be fixed automatically.
- Forwards compatibility is not required, nor is saving data as a previous version. All that is required is for the most recent code to be able to read data saved in any previous version and to save it in the latest data version.
- Optional: the more human-readable the output format, the better, so YAML is preferable to JSON, which is preferable to XML, which in turn is preferable to binary.
I have some ideas about how I could do this myself (giving each serializable class a chain of delegates to convert them through subsequent versions and writing a custom serializer and deserializer using reflection and YamlDotNet), but I wanted to make sure I wasn't re-inventing the wheel before doing so.
So the question is: can anyone point me to an existing library/example/way of working/etc. that satisfies the given criteria for serialization?