JSON.NET未将TypeConverter用于Dictionary键



我正在尝试使用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)方法。因此,我创建了一个名为TimeConverterTypeConverter,它利用了它,就像这样:

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:将属性序列化/反序列化为值,而不是对象以获取详细信息。

事实证明,这是两个不同问题的组合:

  1. 正如@dbc的回答中所解释的,我在TimeConverter.CanConvertFrom()中使用了&&而不是||
  2. 我使用的是Json的第9版。NET,但在中。NET CoreTypeConverter支持直到版本10才实现

使用||并升级到Json。NET 12解决了我的问题。

相关内容

  • 没有找到相关文章

最新更新