Cannot deserialize a class that inherits Dictionary with int as its key
Unable to Deserialize a class that inherits a dictionary when using int as its key. i.e. Dictionary<int, T>. The use case for this is pulling info from a database and storing the identity in the key and it's object data in the value. Below I'm using a string as the value for a simple demonstration.
Instances which do serialize and deserialize are:
- Variable defined as
Dictionary<int, string>(demonstrated below) - Class that inherits a dictionary using a string (
class Foo : Dictionary<string, string>)
Output
{"1":"Item1-data","2":"Item2-data"}
Exception thrown:
'System.ArgumentException' in System.Private.CoreLib.dll An exception of type 'System.ArgumentException' occurred in System.Private.CoreLib.dll but was not handled in user code The value "1" is not of type "System.Int32" and cannot be used in this generic collection.
Test Class
using System.Collections.Generic;
namespace Test.JsonEngines
{
public class DictIntKey : Dictionary<int, string>
{
// No properties here, just helper methods
}
}
Unit Test - Fails
[TestMethod]
public void Utf8DictIntKeyQuickTest()
{
// Assign
var obj1 = new DictIntKey() { StringA = "Helo", IntB = 34 };
obj1.Add(1, "Item1-data");
obj1.Add(2, "Item2-data");
// Object to string
string json1 = Utf8Json.JsonSerializer.ToJsonString(obj1);
Debug.WriteLine($"Utf8 - Before Output:\r\n{json1}");
// Throws exception when converting string to object
var obj2 = Utf8Json.JsonSerializer.Deserialize<DictIntKey>(json1);
string json2 = Utf8Json.JsonSerializer.ToJsonString(obj2);
Debug.WriteLine($"Utf8 - After Output:\r\n{json2}");
Assert.AreEqual(json1, json2);
}
Output before exception
Utf8 - Before Output:
{"1":"Item1-data","2":"Item2-data"}
Unit Test - Passes
This snip below shows that you can use a Dictionary<int, T>.
[TestMethod]
public void Utf8DictIntKeySimpleTest()
{
// Assign
var obj1 = new Dictionary<int, string>();
obj1.Add(1, "Item1-data");
obj1.Add(2, "Item2-data");
string json1 = Utf8Json.JsonSerializer.ToJsonString(obj1);
var obj2 = Utf8Json.JsonSerializer.Deserialize<Dictionary<int, string>>(json1);
string json2 = Utf8Json.JsonSerializer.ToJsonString(obj2);
Debug.WriteLine($"Utf8 - Before Output:\r\n{json1}");
Debug.WriteLine($"Utf8 - After Output:\r\n{json2}");
Assert.AreEqual(json1, json2);
}
Output:
Utf8 - Before Output:
{"1":"Item1-data","2":"Item2-data"}
Utf8 - After Output:
{"1":"Item1-data","2":"Item2-data"}
As a workaround you might be able to add a formatter like this:
public class CustomDictionaryFormatter : IJsonFormatter<DictIntKey>
{
public DictIntKey Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
{
return new DictIntKey(formatterResolver.GetFormatterWithVerify<Dictionary<int, string>>().Deserialize(ref reader, formatterResolver));
}
public void Serialize(ref JsonWriter writer, DictIntKey value, IJsonFormatterResolver formatterResolver)
{
formatterResolver.GetFormatterWithVerify<Dictionary<int, string>>().Serialize(ref writer, value, formatterResolver);
}
}
Although this is sub optimal since it crates the dictionary twice. Better option would be to write it from scratch.