When an object with a Dictionary Field (or Property) are serialized, the Type information is not written in the stream. As a consequence, the deserialization fails with a Null pointer exception:
System.NullReferenceException: La référence d'objet n'est pas définie à une instance d'un objet.
à xstream.DynamicInstanceBuilder.CreateInstance(Type type)
à xstream.Converters.Collections.DictionaryConverter.EmptyDictionary(XStreamReader reader)
à xstream.Converters.Collections.BaseDictionaryConverter`1.FromXml(XStreamReader reader, UnmarshallingContext context)
à xstream.Unmarshaller.ConvertField(Type fieldType)
à xstream.Unmarshaller.UnmarshalAs(Object result, Type type)
à xstream.Unmarshaller.Unmarshal(Type type)
à xstream.UnmarshallingContext.ConvertOriginal()
à xstream.XStream.FromXml(String s)
The XML looks like (here the property name is Hashtable):
....
<Hashtable>
<entry>
<key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">3</key>
<value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">three</value>
</entry>
<entry>
<key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">2</key>
<value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">two</value>
</entry>
<entry>
<key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">1</key>
<value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">one</value>
</entry>
</Hashtable>
...
Class:
public class ExampleWithCollections
{
public List<String> List;
public Dictionary<int, string> Dictionary;
public Hashtable Hashtable;
public ExampleWithCollections()
{
List = new List<string>();
Dictionary = new Dictionary<int, string>();
Hashtable = new Hashtable();
}
}
Please note that the problem does not occur if an instance of Dictionary is serialized directly as the "root" object, as the type (class) information is written to the stream:
<DictionaryOfInt32AndString class="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<entry>
<key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">1</key>
<value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">one</value>
</entry>
<entry>
<key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">2</key>
<value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">two</value>
</entry>
<entry>
<key class="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">3</key>
<value class="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">three</value>
</entry>
</DictionaryOfInt32AndString>
Testclass to reproduce the problem:
ProblemWithDictionaryTest.cs
Output of the test class before and after fix
test_result_after.txt
test_result_before.txt
Fix proposal:
- add attribute dict-type with type information when serialized
- read attribute dict-type when deserializing in order to instantiate the appropriate type
the serialized Dictionary now looks like:
<ExampleWithCollections class=
....
<Dictionary dict-type="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]">
<entry>
....
Fixed files are attached:
BaseDictionaryConverter.cs
DictionaryConverter.cs
HashtableConverter.cs
Please not that the type information is redundantly serialized in case an instance of a Dictionary is serialized as the "root" object:
<DictionaryOfInt32AndString class="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" dict-type="System.Collections.Generic.Dictionary`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]">
<entry>
Unittests are green after the fix.