C#中System.Text.Json浮点数序列化问题
解决System.Text.Json序列化float类型保留小数部分的问题
问题本质
System.Text.Json默认的浮点数序列化逻辑会自动省略末尾的.0,因为从数值等价性出发,4和4.0没有区别,库的默认行为优先输出紧凑的JSON结构。你尝试的AllowNamedFloatingPointLiterals是用来支持NaN、Infinity这类特殊浮点值的,和保留.0无关;而WriteAsString如果没生效,大概率是配置没有正确应用到目标对象或属性上。
可行解决方案
1. 正确配置WriteAsString强制转为字符串
确保序列化选项的NumberHandling设置正确,全局或针对单个属性生效:
using System.Text.Json; using System.Text.Json.Serialization; // 全局配置 var globalOptions = new JsonSerializerOptions { NumberHandling = JsonNumberHandling.WriteAsString }; var globalData = new { Value = 4.0f }; string globalJson = JsonSerializer.Serialize(globalData, globalOptions); // 输出: {"Value":"4.0"} // 单个属性配置 public class DataModel { [JsonPropertyName("value")] [JsonNumberHandling(JsonNumberHandling.WriteAsString)] public float Value { get; set; } } var propertyData = new DataModel { Value = 4.0f }; string propertyJson = JsonSerializer.Serialize(propertyData); // 输出: {"value":"4.0"}
2. 自定义转换器保留数值类型并强制输出.0
如果需要保持JSON中的数值类型(不转字符串),可以自定义JsonConverter<float>来控制输出格式:
public class FloatDecimalPreserveConverter : JsonConverter<float> { public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return reader.GetSingle(); } public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options) { // 判断是否为整数形式的浮点数,强制输出带.0的格式 if (Math.Abs(value - Math.Floor(value)) < float.Epsilon) { writer.WriteRawValue($"{value}.0"); } else { writer.WriteNumberValue(value); } } }
使用时在序列化选项中注册转换器:
var converterOptions = new JsonSerializerOptions { Converters = { new FloatDecimalPreserveConverter() } }; var converterData = new { IntFloat = 4.0f, NormalFloat = 3.14f }; string converterJson = JsonSerializer.Serialize(converterData, converterOptions); // 输出: {"IntFloat":4.0,"NormalFloat":3.14}
已知限制
在.NET 8及更早版本中,System.Text.Json确实没有内置配置项可以直接让数值类型的浮点数强制保留.0,默认逻辑会自动优化掉末尾无意义的小数部分。因此自定义转换器是保持数值类型前提下实现需求的唯一可行方式。
内容的提问来源于stack exchange,提问作者benjamin Hardy
相关产品推荐
相关产品推荐

