【问题标题】:JsonSerializer - serialize decimal places with 'N2' formattingJsonSerializer - 使用“N2”格式序列化小数位
【发布时间】:2013-07-26 03:43:00
【问题描述】:

我正在使用 Newtonsoft.Json.JsonSerializer 序列化小数。

如何将其设置为序列化只有 1 个小数位的十进制数以在末尾使用 0。

即3.5 序列化为“3.50”?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4 json.net jsonserializer


    【解决方案1】:

    您必须编写自己的自定义 JsonConverter 并使用它来拦截 decimal 类型,以便您可以更改它的序列化方式。这是一个例子:

    public class DecimalFormatConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(decimal));
        }
    
        public override void WriteJson(JsonWriter writer, object value, 
                                       JsonSerializer serializer)
        {
            writer.WriteValue(string.Format("{0:N2}", value));
        }
    
        public override bool CanRead
        {
            get { return false; }
        }
    
        public override object ReadJson(JsonReader reader, Type objectType,
                                     object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();    
        }
    }   
    

    要使用它,只需将此自定义转换器的新实例传递给SerializeObject 方法:

    var json = JsonConvert.SerializeObject(yourObject, new DecimalFormatConverter());
    

    【讨论】:

    • 注意,文化应该在string.Format中指定。否则你可能会遇到奇怪的“错误”。
    • 可能对某人有用:如果您不想在值周围输出双引号,则可以使用 WriteRawValue 代替
    • {0:N2} 将包含逗号。如果您使用 WriteRawValue 并且逗号是字符串的一部分,您将收到错误消息。
    • 请记住使用 CultureInfo.InvariantCulture writer.WriteValue(string.Format(CultureInfo.InvariantCulture, "{0:N2}", value)); 格式化字符串
    【解决方案2】:

    接受的答案是正确的,但在接受的答案上扩展了 cmets:

    如果您希望 JSON 中的小数是数字而不是字符串,则需要使用 WriteRawValue 并使用 :0.00 而不是 :N2 进行字符串格式化(因为 N2 包括千位分隔符逗号和其他文化特定的数字格式会破坏您的 JSON)

    public class DecimalFormatConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(decimal);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteRawValue($"{value:0.00}");
        }
    
        public override bool CanRead => false;
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    这是输出与接受的答案相比的差异。

    # writer.WriteRawValue($"{value:0.00}");
    {
        "MyDecimal": 3.50,
        "MyBiggerDecimal": 12345.50
    }
    
    # writer.WriteValue($"{value:N2}");
    {
        "MyDecimal": "3.50",
        "MyBiggerDecimal": "12,345.50"
    }
    

    注意 - 对于 OP 的特定问题,可接受的答案是正确的,即将3.5 序列化为"3.50",但我到这里是想将3.5 序列化为3.50(不带字符串引号)。

    【讨论】:

    • stackoverflow.com/a/39526179/4805491 该答案使用number.ToString(CultureInfo.InvariantCulture)。方法对吗?
    • 是的,如果您的输出旨在用于机器对机器的通信,那么您应该始终在 .NET 中明确指定 InvariantCulture,而 JSON 天生就是如此。如果你不这样做,结果将根据代码运行的任何文化进行格式化。例如在荷兰服务器上,接受的答案将返回“3,50”,而不是“3.50”。
    • 记住使用不变的文化:writer.WriteRawValue(FormattableString.Invariant($"{value:0.00}"));
    • 如果你的模型有十进制类型的属性? (可为空)您需要将 CanConvert 方法更新为return objectType == typeof(decimal) || objectType == typeof(decimal?);,否则它将无法与可为空的属性一起使用。
    • 使用System.Text而不是newtonsoft时可以吗? stackoverflow.com/questions/71255259/…
    猜你喜欢
    • 1970-01-01
    • 2020-02-05
    • 2012-11-03
    • 2011-10-31
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多