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

使用System.Text.Json序列化.NET对象时double属性值精度异常求助

解决System.Text.Json序列化double时的精度显示问题

问题原因

你遇到的现象确实和double的二进制浮点特性直接相关:

  • 像70.8这样的十进制小数无法被二进制浮点数精确存储,在内存中它实际的二进制表示对应的十进制近似值就是70.799999999999997。
  • 类实例中显示70.8,是因为.NET在调试器、ToString()等场景下会自动对这个近似值做舍入处理,以更友好的十进制形式展示;但System.Text.Json默认会输出double的精确二进制浮点对应十进制字符串,所以就出现了看似“数值变化”的情况。

解决方案

以下两种方法可以在不将double转为字符串的前提下,让JSON输出更友好的数字格式:

方法1:自定义转换器,按指定精度舍入输出

创建一个JsonConverter<double>的实现,序列化时主动将double值舍入到指定小数位:

public class DoubleRoundingConverter : JsonConverter<double>
{
    private readonly int _decimalPlaces;

    public DoubleRoundingConverter(int decimalPlaces = 1)
    {
        _decimalPlaces = decimalPlaces;
    }

    public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.GetDouble();
    }

    public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
    {
        var roundedValue = Math.Round(value, _decimalPlaces);
        writer.WriteNumberValue(roundedValue);
    }
}

修改Well类的序列化方法,配置使用该转换器:

public void serialiseJSON()
{
    string fileName = "well.json";
    var options = new JsonSerializerOptions
    {
        Converters = { new DoubleRoundingConverter(1) }, // 根据需求调整小数位数
        WriteIndented = true // 可选,格式化JSON结构
    };
    // 注意:原代码中JsonSerialiser拼写错误,应为JsonSerializer
    string jsonString = JsonSerializer.Serialize(this, options);
    File.WriteAllText(fileName, jsonString);
}

这种方法适合你明确知道业务所需精度的场景,比如长度值只需保留1位小数。

方法2:输出double的最短精确表示

利用double.ToString("G17")格式,输出能唯一标识该double值的最短十进制字符串,既保证精度又避免冗长数字:

public class DoubleShortFormatConverter : JsonConverter<double>
{
    public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.GetDouble();
    }

    public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
    {
        // G17格式会输出最短的、能精确还原原double值的十进制字符串
        writer.WriteRawValue(value.ToString("G17"));
    }
}

同样在序列化配置中添加该转换器即可,这种方法适合需要保留double原始精度,但不想看到冗长近似值的场景。

注意事项

  • 两种方法反序列化后得到的double值,和原实例中的值在二进制层面是等价的(因为原double本身就是近似值),不会丢失业务精度。
  • 原代码中的JsonSerialiser是拼写错误,正确的类名是JsonSerializer。

内容的提问来源于stack exchange,提问作者Suhaib Ahmad

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 22:23:19