I was trying out Json.net's ability to serialize and deserialize dictionaries, and thanks to this post I was able to find a good solution to serializing dictionaries in a simple way.
It was working great, but in a certain circumstance it broke in a (to me) nonsensical way such that I couldn't help but spend the next three hours debugging.
Here is the problem. When serializing this class
public class ReferenceTesting
{
public List<Scenario> scenarios = new List<Scenario>();
private Dictionary<Scenario, float> _Dict = new Dictionary<Scenario, float>();
[JsonProperty]
public List<KeyValuePair<Scenario, float>> SerializedDict
{
get { return _Dict.ToList(); }
set { _Dict = value.ToDictionary(x => x.Key, x => x.Value); }
}
public ReferenceTesting(int number = 0)
{
for (int i = 0; i < number; i++)
{
Scenario s1 = new Scenario();
scenarios.Add(s1);
_Dict.Add(s1, i);
}
}
public override string ToString()
{
string s = "";
for (int i = 0; i < scenarios.Count(); i++)
{
Scenario scenario = scenarios[i];
s += $"scenario{i} \n";
}
foreach (KeyValuePair<Scenario, float> scenario in SerializedDict)
{
s += $"Key: {scenario.Key}, Value: {scenario.Value} \n";
}
return s;
}
}
Everything works as expected, meaning when I instantiate
new Reference(3);
and then serialize and deserialize, I end up with an object with as expected 3 items in the list, and 3 items in the dictionary.
Output:
scenario0
scenario1
scenario2
Key: Scenario, Value: 0
Key: Scenario, Value: 1
Key: Scenario, Value: 2
However, by adding the default constructor
public ReferenceTesting() { }
the serialization works, writing out 3 items in list and dictionary, but deserialization does not work with the property. Meaning I end up with
scenario0
scenario1
scenario2
as output.
The big surprise with this is that the two constructors do the exact same thing - which is nothing when number = 0 (which it is when Json.net creates it, I doublechecked). So this means that the serializer has to be doing something under the hood to treat the property differently if there is or is not a default constructor.