我正在尝试使用JSON。NET来序列化/反序列化SortedDictionary<Time, T>
,其中Time
是我的项目中的一个自定义类,而T
是一些不需要包含在这里的类型。
序列化非常有效。以这本字典为例:
var dictionary = new SortedDictionary<Time, T> {
[Time.Parse("7:00AM")] = ...,
[Time.Parse("8:00AM")] = ...,
[Time.Parse("9:00AM")] = ...
};
(Time.Parse()
是一个从字符串输入构造Time
对象的简单方法。(现在,如果我运行JsonConvert.SerializeObject(dictionary, Formatting.Indented)
,我会得到这样的结果:
{
"7:00AM": ...,
"8:00AM": ...,
"9:00AM": ...
}
这是因为Time
类覆盖了ToString()
方法,因此字典键可以很容易地转换为字符串。
不幸的是,反序列化在这里失败了。给定上一个例子的输出,运行JsonConvert.DeserializeObject<SortedDictionary<Time, T>>(previousOutput)
会产生一个异常:
Newtonsoft。Json。JsonSerializationException
无法将字符串"7:00AM"转换为字典键类型"[…].Time"。请创建一个TypeConverter以从字符串转换为键类型对象。[…]
好吧,这很有道理。毕竟,如果没有某种类型的转换器,JSON就无从谈起。NET来了解如何处理此问题。但是,我的Time
类已经有了一个Parse(string)
方法。因此,我创建了一个名为TimeConverter
的TypeConverter
,它利用了它,就像这样:
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);
}
}
然后,我在Time
类声明中添加了一个TypeConverter
属性:
[TypeConverter(typeof(TimeConverter))]
public class Time : IComparable<Time>
{
...
}
然而,这并没有奏效。仍然抛出完全相同的错误。此外,我尝试在TimeConverter
方法中放置断点,但它们从未被触发。JSON。NET似乎完全忽略了我的转换器。我做错了什么?
如果传入类型为typeof(string)
或,则需要修改TimeConverter.CanConvertFrom()
以返回true。基类可以转换类型:
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
}
从引用源可以看出,当传入类型为typeof(InstanceDescriptor)
时,基类的CanConvertFrom()
只返回true
。因此,当传递typeof(string)
时,CanConvertFrom()
返回false,并且从未调用转换方法。
这里可以找到使用Time
类的实体模型的原始问题的演示。
可以在这里找到固定的、工作的TypeConverter
的演示。
但是请注意,如果您正在使用。NET Core,对类型转换器的支持仅在Json时才添加。NET 10.0.1。如果您的目标是netstandard1.0+或。NET Core,并且正在使用早期版本的Json。NET,您将需要升级。参见Json。Net:将属性序列化/反序列化为值,而不是对象以获取详细信息。
事实证明,这是两个不同问题的组合:
- 正如@dbc的回答中所解释的,我在
TimeConverter.CanConvertFrom()
中使用了&&
而不是||
- 我使用的是Json的第9版。NET,但在中。NET Core,
TypeConverter
支持直到版本10才实现
使用||
并升级到Json。NET 12解决了我的问题。