Dot-Net

Json.NET 用最少的小數位序列化浮點/雙精度,即沒有多餘的“.0”?

  • January 16, 2014

在序列化浮點數和雙精度數時,如果數字不包含任何小數部分,Json.NET 總是在末尾添加“.0”。我想知道是否有一種簡單的方法可以繞過它,從而產生更緊湊的表示?序列化包含許多數字的對象時,額外的句點和零會加起來。

例如,執行此程式碼時:

JsonConvert.SerializeObject(1.0);

我希望(並且想要)這個結果:

"1"

但相反,我得到:

"1.0"

我查看了原始碼並註意到它是故意添加到送出0319263“…-Fixed JsonConvert to always write a floating point number with a decimal place…”)中,它執行的程式碼基本上看起來像:

   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 規範似乎不需要它。
  2. 有沒有簡單的方法繞過它?

1. 發生這種變化的原因可能是什麼?

規範不需要它,但它也不允許它。

我的猜測是它允許對 Json.NET 進行更好的類型檢查(如果他們在某處有它),或者它是一個“以防萬一”的東西,允許區分整數和浮點類型。

來自 Json.org

2.有沒有簡單的方法繞過它?

EnsureDecimalPlace()沒那麼容易,但是如果你真的想要的話,你可以在改成 simple 之後重新編譯你自己的 Json.NET 版本return text;

作為問題 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)
       {
           decimal decimalValue = (decimal)value;
           int precision = (Decimal.GetBits(decimalValue)[3] >> 16) & 0x000000FF;
           return precision == 0;
       }
       else if (value is float || value is double)
       {
           double doubleValue = (double)value;
           return doubleValue == Math.Truncate(doubleValue);
       }

       return false;
   }
}

這將保留十進制類型值的精度。如果您希望忽略小數值的精度,可以使 IsWholeValue() 函式的小數部分與浮點/雙精度部分的工作方式相同:

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

       return false;
   }

無論哪種情況,要使用上面的程式碼,只需像這樣呼叫序列化程序:

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

引用自:https://stackoverflow.com/questions/21153381