我有段將彈性格式 JSON 反序列化為 Dictionary<string, object> 的程式,在處理小點數時遇上問題。假設 JSON 來源長這樣:

[

  {
    "ItemNo": "A-100",
    "Value": 127
  },
  {
    "ItemNo": "A-101",
    "Value": 3.1416
  },
  {
    "ModelId": "B-52",
    "Value": 0.00000000035
  },
  {
    "ModelId": "B-1",
    "Value": 9.87987987987987987
  }
]

解析程式如下:

static void Main(string[] args)
{
    var srcJson = File.ReadAllText("sample.json");
    Console.WriteLine(srcJson);
    var data = JsonConvert.DeserializeObject<Dictionary<string, object>[]>(srcJson);
    Console.WriteLine(JsonConvert.SerializeObject(data, Formatting.Indented));
    Console.ReadLine();
}

原本預期 Value 欄位會解析成 decimal 型別,事實不然。反序列化後數值有變,再序列化後 0.00000000035 變成 3.5E-10, 9.87987987987987987 變成 9.87987987987988,損失部分精確度。

由科學記號及位數取 15 位,判斷它們是被當成 double,透過檢查 dict["Value"].GetType() 可驗證這點。

幸好,Json.NET 有個序列化參數 FloatParseHandling,設成 FloatParseHandling.Decimal 可強制將浮點數字解析成 Decimal,問題排除。

Issue of precison loss while JSON deserialization and how to avoid it in Json.NET.


Comments

# by Cloud

黑大, 使用 System.Text.Json 可正確處理小數數值解析問題 var data = JsonSerializer.Deserialize<Dictionary<string, object>[]>(srcJson); Console.WriteLine(JsonSerializer.Serialize(data, new JsonSerializerOptions() { WriteIndented = true }));

# by Jeffrey

to Cloud, 正好奇 System.Text.Json 會不會遇到同樣問題,謝謝分享。

Post a comment