反序列化时如何去除尾随零?如何配置该自定义行为
关于Decimal序列化/反序列化去除尾随零的解决方案
嘿,刚好之前处理过类似的需求,来给你详细说说:
一、如何实现去除尾随零(以.NET常用JSON库为例)
先澄清下:你示例里从decimal类型输出JSON,这其实是序列化过程;如果是从JSON字符串转decimal并处理尾随零,那是反序列化——两种场景我都给你覆盖到:
1. 使用Newtonsoft.Json(Json.NET)
序列化时自动去除尾随零
可以直接通过配置DecimalFormatHandling实现,或者用自定义转换器更灵活:
// 简单配置方式 var settings = new JsonSerializerSettings { DecimalFormatHandling = DecimalFormatHandling.Currency, Formatting = Formatting.Indented // 可选,美化输出格式 }; decimal value = 1.99000m; string json = JsonConvert.SerializeObject(value, settings); // 输出结果:"1.99"
如果需要更精细的控制,写个自定义转换器:
public class TrimTrailingZeroDecimalConverter : JsonConverter<decimal> { public override decimal ReadJson(JsonReader reader, Type objectType, decimal existingValue, bool hasExistingValue, JsonSerializer serializer) { // 反序列化场景:处理JSON字符串里的尾随零 string strValue = reader.Value.ToString(); var trimmed = strValue.TrimEnd('0').TrimEnd('.'); return decimal.Parse(string.IsNullOrEmpty(trimmed) ? "0" : trimmed); } public override void WriteJson(JsonWriter writer, decimal value, JsonSerializer serializer) { // 序列化场景:把decimal转成无尾随零的字符串 var trimmed = value.ToString().TrimEnd('0').TrimEnd('.'); writer.WriteValue(string.IsNullOrEmpty(trimmed) ? "0" : trimmed); } }
使用时在配置里添加转换器:
var settings = new JsonSerializerSettings { Converters = new List<JsonConverter> { new TrimTrailingZeroDecimalConverter() } }; string json = JsonConvert.SerializeObject(1.99000m, settings); // 输出"1.99"
2. 使用System.Text.Json(.NET Core/.NET 5+默认)
同样通过自定义转换器实现:
public class TrimTrailingZeroDecimalConverter : JsonConverter<decimal> { public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { string strValue = reader.GetString()!; var trimmed = strValue.TrimEnd('0').TrimEnd('.'); return decimal.Parse(string.IsNullOrEmpty(trimmed) ? "0" : trimmed); } public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options) { var trimmed = value.ToString().TrimEnd('0').TrimEnd('.'); writer.WriteStringValue(string.IsNullOrEmpty(trimmed) ? "0" : trimmed); } }
配置并使用:
var options = new JsonSerializerOptions { Converters = { new TrimTrailingZeroDecimalConverter() }, WriteIndented = true // 可选美化输出 }; string json = JsonSerializer.Serialize(1.99000m, options); // 输出"1.99"
二、关于“去除尾随零是否是bug”的疑问
这个观点是从decimal类型的设计初衷出发的:decimal的尾随零是用来表示精度语义的——比如1.99000m意味着值精确到十万分位,而1.99m是精确到百分位,两者在业务精度要求上有细微差别。所以多数序列化库默认保留尾随零,是为了完整保留decimal的精度信息,避免丢失业务语义。
但这绝对不是“bug”!如果你的业务场景不需要这些精度标识(比如前端展示只需要简洁数值),完全可以通过上面的配置/自定义转换器实现去除尾随零的行为,这属于业务需求驱动的定制化配置,合理且完全可行。
内容的提问来源于stack exchange,提问作者Leonardo
相关产品推荐
相关产品推荐

