.net - Json.NET 以最小的小数位数序列化 float/double,即没有冗余 ".0"?

标签 .net json floating-point json.net

序列化 float 和 double 时,如果数字不包含任何小数部分,Json.NET 总是在末尾添加“.0”。我想知道是否有一种简单的方法可以绕过这个问题,从而得到更紧凑的表示?当序列化包含许多数字的对象时,额外的句点和零会增加。

例如,运行此代码时:

JsonConvert.SerializeObject(1.0);

我期望(并且想要)这个结果:

"1"

但我得到的是:

"1.0"

我查看了源代码,发现它是故意添加到commit 0319263中的(“...-修复了 JsonConvert 以始终​​写入带小数位的 float ...”)它运行的代码基本上如下所示:

    private static string EnsureDecimalPlace(double value, string text)
    {
        if (double.IsNaN(value) || double.IsInfinity(value) ||
            text.IndexOf('.') != -1 || text.IndexOf('E') != -1 ||
            text.IndexOf('e') != -1)
        {
            return text;
        }

        return text + ".0";
    }

因此,我想知道:

  1. 造成这一变化的原因可能是什么? JSON specification好像不需要。

  2. 有没有简单的方法可以绕过它?

最佳答案

作为问题 2 的替代答案(假设您不想经历编译自己的自定义版本的 Json.NET 源代码的麻烦),您可以创建自己的自定义 JsonConverter 类来处理小数、浮点和双值。这是我正在使用的版本:

    class DecimalJsonConverter : JsonConverter
    {
        public DecimalJsonConverter()
        {
        }

        public override bool CanRead
        {
            get
            {
                return false;
            }
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
        }

        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(decimal) || objectType == typeof(float) || objectType == typeof(double));
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (DecimalJsonConverter.IsWholeValue(value))
            {
                writer.WriteRawValue(JsonConvert.ToString(Convert.ToInt64(value)));
            }
            else
            {
                writer.WriteRawValue(JsonConvert.ToString(value));
            }
        }

        private static bool IsWholeValue(object value)
        {
            if (value is decimal decimalValue)
            {
                int precision = (Decimal.GetBits(decimalValue)[3] >> 16) & 0x000000FF;
                return precision == 0;
            }
            else if (value is float floatValue)
            {
                return floatValue == Math.Truncate(floatValue);
            }
            else if (value is double doubleValue)
            {
                return doubleValue == Math.Truncate(doubleValue);
            }

            return false;
        }
    }

这将保留小数类型值的精度。如果您希望忽略小数值的精度,可以使 IsWholeValue() 函数的小数部分与 float/double 部分的工作方式相同:

        private static bool IsWholeValue(object value)
        {
            if (value is decimal decimalValue)
            {
                return decimalValue == Math.Truncate(decimalValue);
            }
            else if (value is float floatValue)
            {
                return floatValue == Math.Truncate(floatValue);
            }
            else if (value is double doubleValue)
            {
                return doubleValue == Math.Truncate(doubleValue);
            }

            return false;
        }

无论哪种情况,要使用上面的代码,只需像这样调用序列化器:

string json = JsonConvert.SerializeObject(value, new DecimalJsonConverter())

关于.net - Json.NET 以最小的小数位数序列化 float/double,即没有冗余 ".0"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21153381/

相关文章:

javascript - ReactJs中如何显示Json数据

C/C++ 代码不适用于 DEV C++。 (浮点或类型)

.net - 如何在 aspx 页面上动态显示视频播放器

c# - 自定义 Visual Studio 错误

ruby-on-rails - 网络模拟 : Rspec - Test Facebook Validation by using JSON response

C++ NaN 字节表示在赋值期间发生变化

performance - 在单精度CPU上进行 double 计算

c# - nlog 登录到另一个目录

.net - 如何调试asp.net mvc 4 源代码?

ios - 从 JSON 中快速解析多个图像