JSON.NET未使用自定义TypeConverter处理SortedDictionary键导致反序列化失败
为什么自定义TypeConverter没有生效
JSON.NET 在处理字典键的序列化/反序列化分支时,不会自动扫描自定义类型上标注的TypeConverter特性完成字符串与目标键类型的转换。
- 你看到序列化输出正常,完全是JSON.NET的默认回退逻辑在起作用:遇到非字符串类型的字典键时,它会直接调用键对象的
ToString()方法生成JSON的键名,这个过程根本没有走到你写的TimeConverter逻辑。 - 反序列化阶段抛出异常,本质是字典键的解析逻辑完全独立于常规对象序列化管线,默认不会关联
TypeConverter做反向字符串转换,所以你在TimeConverter里加的断点永远不会被触发。
可行的解决方案
方案1:实现原生JsonConverter处理Time类型(推荐)
直接为Time类写JSON.NET专属的转换器,是最贴合框架运行逻辑的方式——不管Time类型是作为字典键、对象属性还是集合元素出现,都能被正常识别和处理。
示例代码:
public class TimeJsonConverter : JsonConverter { // 仅对Time类型生效,避免影响其他类型的序列化逻辑 public override bool CanConvert(Type objectType) { return objectType == typeof(Time); } // 反序列化:把JSON字符串值解析为Time实例 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.String) { return Time.Parse((string)reader.Value); } throw new JsonSerializationException($"无法将{reader.TokenType}类型的JSON标记转换为Time对象"); } // 序列化:把Time实例转为标准字符串格式 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var timeValue = (Time)value; writer.WriteValue(timeValue.ToString()); } }
注册方式二选一即可:
- 给
Time类加标注,全局自动生效:
[JsonConverter(typeof(TimeJsonConverter))] public class Time : IComparable<Time> { // 原有类实现逻辑保持不变 }
- 反序列化时通过配置手动注册,不需要修改
Time类的定义:
var serializeConfig = new JsonSerializerSettings { Converters = { new TimeJsonConverter() } }; var result = JsonConvert.DeserializeObject<SortedDictionary<Time, T>>(jsonOutput, serializeConfig);
方案2:复用已编写的TypeConverter
如果你不想重写转换逻辑,JSON.NET 提供了桥接类TypeConverterJsonConverter,可以把现有.NET体系的TypeConverter适配为JSON.NET可识别的转换器,只需要在序列化配置里手动注册,不需要改动原有TimeConverter和Time类的代码:
var serializeConfig = new JsonSerializerSettings { Converters = { new TypeConverterJsonConverter(typeof(Time)) } }; var result = JsonConvert.DeserializeObject<SortedDictionary<Time, T>>(jsonOutput, serializeConfig);
注册完成后,JSON.NET才会主动读取你之前标注在Time类上的TypeConverter特性,触发对应的转换逻辑。
常见踩坑提醒
JSON.NET 对字典键的处理逻辑和普通类型是完全隔离的:哪怕你给自定义键类型写了完整的TypeConverter,只要是框架内置不识别的非基础类型,不主动注册对应转换器的话,就一定会出现“序列化输出正常、反序列化直接抛转换异常”的问题,因为序列化的回退逻辑和反序列化的严格解析逻辑不是同一套规则。
内容的提问来源于stack exchange,提问作者Jacob Lockard
相关产品推荐
相关产品推荐

