You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

编写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 20:25:39