编写C# JsonConverter处理含Infinity的Dictionary<int, double?>反序列化
问题描述
从API获取的JSON数据中包含一个类型为Dictionary<int, double?>?的属性,该属性的double值有时会返回Infinity字符串,导致直接反序列化失败。需要编写JsonConverter处理此情况,将Infinity转换为default(double?)或0,但不知道如何正确检测并处理该值。
现有代码
internal class InfinityDictionaryToNullJsonConverter : JsonConverter<Dictionary<int, double?>?> { public override Dictionary<int, double?>? Read(ref Utf8JsonReader reader, Type typeToConvert,JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.StartObject) { Type keyType = typeToConvert.GetGenericArguments()[0]; Type valueType = typeToConvert.GetGenericArguments()[1]; if (reader.GetString().Contains("Infinity")) { return new Dictionary<int, double?> { { 0, 0 } }; } } else { var test = reader.GetString(); } return new Dictionary<int, double?> { { 0, 0 } }; } public override void Write(Utf8JsonWriter writer,Dictionary<int, double?>? value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString()); } }
示例JSON数据
{ "TeamRanks": { "0": "Infinity", "1": "1757.739122974623" } }
解决方案
当前代码的核心问题是:当TokenType为StartObject时,无法直接通过reader.GetString()获取对象内部的属性值,必须遍历整个对象的键值对逐个处理。以下是修正后的转换器代码:
internal class InfinityDictionaryToNullJsonConverter : JsonConverter<Dictionary<int, double?>?> { public override Dictionary<int, double?>? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 处理JSON为null的情况 if (reader.TokenType == JsonTokenType.Null) { return null; } // 校验当前是否为对象起始标记 if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException("字典类型需以对象格式序列化"); } var dictionary = new Dictionary<int, double?>(); // 遍历对象所有键值对 while (reader.Read()) { // 遇到对象结束标记时退出循环 if (reader.TokenType == JsonTokenType.EndObject) { break; } // 读取键(JSON中为字符串类型数字) if (reader.TokenType != JsonTokenType.PropertyName) { throw new JsonException("字典键应为属性名格式"); } string keyStr = reader.GetString()!; if (!int.TryParse(keyStr, out int key)) { // 无效整数键可选择跳过或抛出异常,按需调整 reader.Skip(); continue; } // 读取对应的值 reader.Read(); double? value = null; if (reader.TokenType == JsonTokenType.String) { string valueStr = reader.GetString()!; // 检测Infinity字符串,忽略大小写匹配 if (string.Equals(valueStr, "Infinity", StringComparison.OrdinalIgnoreCase)) { value = default(double?); // 此处可替换为0:value = 0; } else if (double.TryParse(valueStr, out double parsedValue)) { value = parsedValue; } // 其他无效字符串可设为null或抛出异常 } // 兼容API直接返回数字而非字符串的情况 else if (reader.TokenType == JsonTokenType.Number) { value = reader.GetDouble(); } dictionary[key] = value; } return dictionary; } public override void Write(Utf8JsonWriter writer, Dictionary<int, double?>? value, JsonSerializerOptions options) { if (value == null) { writer.WriteNullValue(); return; } writer.WriteStartObject(); foreach (var kvp in value) { writer.WritePropertyName(kvp.Key.ToString()); if (kvp.Value.HasValue) { writer.WriteNumberValue(kvp.Value.Value); } else { writer.WriteNullValue(); } } writer.WriteEndObject(); } }
关键说明
- 遍历对象键值对:通过循环调用
reader.Read()逐个读取属性名和对应值,直到遇到EndObject标记。 - 键处理:将JSON中的字符串键转换为int类型,对无效键做跳过处理(也可按需抛出异常)。
- 值处理:判断字符串是否为
Infinity(忽略大小写),匹配则设置为默认值或0;正常字符串尝试解析为double;同时兼容API直接返回数字的场景。 - 写入逻辑修正:原代码直接调用
value.ToString()会输出字典类型名,现在改为正确序列化每个键值对。
内容的提问来源于stack exchange,提问作者Bad Dub
相关产品推荐
相关产品推荐

