Follow @RoyOsherove on Twitter

Solving Binary serialization versioning conflicts

My friend, Jonathan Einav(His blog is, sadly, empty for now) just sent me this by email. It's a solution to a versioning problem he encountered, which he has made public for the community.
This is a a nice approach to deal with binary de-serialization type version changes (and avoid the iterating "Possible version mismatch. Type WindowsApplication1.MyClass has 3 members, number of members deserialized is 4"  SerializationException ).
Here's how he explains it::

Attached are the DeserializationDefaultValueAttribute.cs, DeserializationOldNameAttribute.cs, and the VersionSupportingBinaryFormatter.cs 

I created a reflection surrogate that de-serialize objects using reflection on the current compiled type definition from the loaded SerializtionInfo. I “tricked”  the BinarySerializer by writing a binder that aside from returning the exact type he received he creates the reflection surrogate for every type that the Serializer is deserializing (wouldn’t it be nice if a simple add surrogate with typeof(object) would work…)

Another trick I used for accessing private base class members values from the SerializationInfo.GetValue() is adding the base class name with a + on the recursive calls to the base classes (that’s how I saw the SerializationInfo  holds them, and for some reason it works….what ever happened to encapsulation…. (-: )    

 I also defined the:

  • DeserializationDefaultValueAttribute which can be placed above new fields that are added to new type definitions in order for the de-serialized new type instances from old type definitions will contain a default value (different from the one given by the CLR)
  • DeserializationOldNameAttribute which can be placed above a field that his name (not type!!!) was changed and we want the new field name to contain the old field value after deserialization.

Simply use the VersionSupportingBinaryFormatter.Deserialize() from an IFormatter point of view within a catch block of a BinarySerializer Deserialize attempt that failed due to a type definition change. (Or you can use it all the time, though it is slower then the Binary Formatter because it uses reflection)

This class was not fully tested yet, though it seems to be working fine in all scenarios that I have tested it (base classes, mutual references in the class graph, base private and protected value types and reference types etc).

Do you have a pre-built version of Mock++ handy?

[Cool Tools] Code metrics, dependencies and more metrics