ASP.NET Core 7中System.Text.Json序列化double位数异常问题咨询
System.Text.Json序列化double位数不一致的原因及解决方案
这是预期行为,不是Bug,核心原因和浮点数的本质、System.Text.Json的序列化策略有关:
为什么会出现位数差异?
- 64位double类型的有效精度是15-17位十进制数字,但绝大多数十进制小数无法被二进制浮点数精确表示。System.Text.Json序列化double时,会输出能还原回原始double值的最短十进制字符串——只要两个不同的十进制字符串对应的二进制double完全相同,就会选择更短的那个。
- 你遇到的例子:内存中的
6.5784774568779181和序列化后的6.578477456877918,本质是同一个double值的不同十进制写法;99.999999999999986和99.99999999999999也是如此,反序列化后都会得到内存里的原始值,不存在数据丢失。
和WCF序列化差异的原因
WCF默认使用的DataContractJsonSerializer采用了不同的输出策略:它会固定输出17位有效数字的字符串,哪怕其中包含冗余的尾数位。这种差异只是字符串表示形式不同,对应的实际double值完全一致。
修改NumberHandling无效的原因
JsonNumberHandling配置项主要控制:是否允许序列化NaN/Infinity等特殊浮点值、是否将数字序列化为字符串、是否禁止非标准数字格式。它不会改变System.Text.Json生成double十进制字符串的位数策略,所以修改后问题依旧。
如何和WCF输出保持一致?
如果需要严格对齐WCF的字符串输出格式,可以自定义一个JsonConverter<double>,强制输出17位有效数字:
public class DoubleConverter : 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格式输出17位有效数字,确保和WCF对齐 writer.WriteStringValue(value.ToString("G17", System.Globalization.CultureInfo.InvariantCulture)); } }
然后将这个转换器添加到序列化配置中:
builder.Services.AddControllers() .AddJsonOptions(o => { o.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); o.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; o.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals; // 添加自定义double转换器 o.JsonSerializerOptions.Converters.Add(new DoubleConverter()); });
如果需要和WCF一样将数字作为字符串输出(而非数字类型),可以保留NumberHandling = JsonNumberHandling.WriteAsString,配合上述转换器即可。
内容的提问来源于stack exchange,提问作者Emanuil Boyanov
相关产品推荐
相关产品推荐

