I am attempting to use JSON.NET to serialize/deserialize a SortedDictionary<Time, T>
, where Time
is a custom class in my project, and T
is some type that need not be included here.
Serialization works perfectly. Take this dictionary, for example:
var dictionary = new SortedDictionary<Time, T> {
[Time.Parse("7:00AM")] = ...,
[Time.Parse("8:00AM")] = ...,
[Time.Parse("9:00AM")] = ...
};
(Time.Parse()
is a simple method that constructs Time
objects from a string input.) Now, if I run JsonConvert.SerializeObject(dictionary, Formatting.Indented)
, I get something like this:
{
"7:00AM": ...,
"8:00AM": ...,
"9:00AM": ...
}
This is because the Time
class overrides the ToString()
method, so the dictionary keys can easily be converted to strings.
Unfortunately, deserialization fails here. Given the output of the last example, running JsonConvert.DeserializeObject<SortedDictionary<Time, T>>(previousOutput)
produces an exception:
Newtonsoft.Json.JsonSerializationException
Could not convert string '7:00AM' to dictionary key type '[...].Time'. Create a TypeConverter to convert from the string to the key type object. [...]
Okay, that makes sense. After all, without some kind of converter, there is no way for JSON.NET to know how to handle this. However, my Time
class already has a Parse(string)
method. So, I created a TypeConverter
called TimeConverter
that utilizes it, like so:
public class TimeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) && base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return value is string s ? Time.Parse(s) : base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
return destinationType == typeof(string) && value is Time t
? t.ToString()
: base.ConvertTo(context, culture, value, destinationType);
}
}
I then added a TypeConverter
attribute to the Time
class declaration:
[TypeConverter(typeof(TimeConverter))]
public class Time : IComparable<Time>
{
...
}
However, this did not work. The exact same error is still thrown. Additionally, I tried placing breakpoints in the TimeConverter
methods, but they were never triggered. JSON.NET seems to be completely ignoring my converter. What am I doing wrong?