Some gotchas in backward compatibility C# with Example



Some gotchas in backward compatibility C# with Example

This small example shows how you can lose backward compatibility in your programs if you do not take care in 
advance about this. And ways to get more control of serialization process 
At first, we will write an example of the first version of the program: 
Version 1 
[Serializable] 
class Data 
{ 
[OptionalField] 
private int _version; 
public int Version 
{ 
get { return _version; } 
set { _version = value; } 
} 
} 
And now, let us assume that in the second version of the program added a new class. And we need to store it in an 
array. 
Now code will look like this: 
 

Version 2 
[Serializable] 
class NewItem 
{ 
[OptionalField] 
private string _name; 
public string Name 
{ 
get { return _name; } 
set { _name = value; } 
} 
} 
[Serializable] 
class Data 
{ 
[OptionalField] 
private int _version; 
public int Version 
{ 
get { return _version; } 
set { _version = value; } 
} 
[OptionalField] 
private List _newItems; 
public List NewItems 
{ 
get { return _newItems; } 
set { _newItems = value; } 
} 
} 
And code for serialize and deserialize 
private static byte[] SerializeData(object obj) 
{ 
var binaryFormatter = new BinaryFormatter(); 
using (var memoryStream = new MemoryStream()) 
{ 
binaryFormatter.Serialize(memoryStream, obj); 
return memoryStream.ToArray(); 
} 
} 
private static object DeserializeData(byte[] bytes) 
{ 
var binaryFormatter = new BinaryFormatter(); 
using (var memoryStream = new MemoryStream(bytes)) 
return binaryFormatter.Deserialize(memoryStream); 
} 
And so, what would happen when you serialize the data in the program of v2 and will try to deserialize them in the 
program of v1? 
You get an exception: 
 

System.Runtime.Serialization.SerializationException was unhandled 
Message=The ObjectManager found an invalid number of fixups. This usually indicates a problem in 
the Formatter.Source=mscorlib 
StackTrace: 
at System.Runtime.Serialization.ObjectManager.DoFixups() 
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, 
   BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage 
methodCallMessage) 
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream 
serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, 
IMethodCallMessage methodCallMessage) 
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream 
serializationStream) 
at Microsoft.Samples.TestV1.Main(String[] args) in c:\Users\andrew\Documents\Visual Studio 
2013\Projects\vts\CS\V1 Application\TestV1Part2\TestV1Part2.cs:line 29 
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) 
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback 
callback, Object state) 
at System.Threading.ThreadHelper.ThreadStart() 
Why? 
The ObjectManager has a different logic to resolve dependencies for arrays and for reference and value types. We 
added an array of new the reference type which is absent in our assembly. 
When ObjectManager attempts to resolve dependencies it builds the graph. When it sees the array, it can not fix it 
immediately, so that it creates a dummy reference and then fixes the array later. 
And since this type is not in the assembly and dependencies can’t be fixed. For some reason, it does not remove the 
array from the list of elements for the fixes and at the end, it throws an exception “IncorrectNumberOfFixups ”. 
It is some ‘gotchas ’ in the process of serialization. For some reason, it does not work correctly only for arrays of new 
reference types. 
A Note: 
Similar code will work correctly if you do not use arrays with new classes 
And the first way to fix it and maintain compatibility? 
Use a collection of new structures rather than classes or use a dictionary(possible classes), because a 
dictionary it ’s a collection of keyvaluepair(it ’s structure) 
Use ISerializable, if you can't change the old code 

0 Comment's

Comment Form

Submit Comment