如何使用Newtonsoft将JSON数字精准读取为字符串?
解决方案:用Newtonsoft保留JSON数字的原始字符串格式
问题回顾
需要实现JSON的反序列化-处理-序列化全流程,要求保留数字的原始格式(包括末尾零、科学计数法、超大整数),避免转为数值类型后丢失精度或格式变化。优先使用Newtonsoft.Json。
实现思路
核心是在反序列化阶段就保留数字的原始字符串表示,而非自动转换为数值类型。通过JsonTextReader关闭自动数值解析,再递归遍历所有JSON节点,将数值类型的节点替换为对应的字符串节点,确保原始格式完全保留。
完整代码
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.IO; public static class JsonNumberHelper { public static JToken DeserializeNumbersAsString(string json) { using var reader = new JsonTextReader(new StringReader(json)) { // 关闭浮点数自动解析以保留原始字符串;关闭日期解析避免数字被误判为日期 FloatParseHandling = FloatParseHandling.None, DateParseHandling = DateParseHandling.None }; var token = JToken.ReadFrom(reader); ReplaceNumberTokensWithStrings(token); return token; } private static void ReplaceNumberTokensWithStrings(JToken token) { switch (token.Type) { case JTokenType.Object: foreach (var property in ((JObject)token).Properties().ToList()) { ReplaceNumberTokensWithStrings(property.Value); } break; case JTokenType.Array: foreach (var item in ((JArray)token).ToList()) { ReplaceNumberTokensWithStrings(item); } break; case JTokenType.Integer: case JTokenType.Float: var originalNumberText = ((JValue)token).ToString(Formatting.None); ((JValue)token).Value = originalNumberText; ((JValue)token).Type = JTokenType.String; break; } } } // 测试代码 var json = """ [{ "foobar1": 21.37000, "foobar2": 0.0000000000000000001000, "foobar3": 1.1000E-19, "aReallyBigInteger" : 1111199999999999999999999999999999999911111 }] """; var processedToken = JsonNumberHelper.DeserializeNumbersAsString(json); Console.WriteLine(processedToken.ToString(Formatting.Indented));
代码说明
- JsonTextReader配置:
FloatParseHandling.None让浮点数以原始字符串形式读取,DateParseHandling.None避免数字被误解析为日期; - 递归节点替换:遍历JSON所有节点,将整数(Integer)和浮点数(Float)类型的
JValue替换为字符串类型,替换时使用节点的原始字符串表示(通过ToString(Formatting.None)获取); - 格式保留:不管是末尾带零的小数、科学计数法表示的极小值,还是超出常规数值类型范围的超大整数,都能完整保留原始格式。
输出结果
运行代码后,输出将完全符合预期:
[ { "foobar1": "21.37000", "foobar2": "0.0000000000000000001000", "foobar3": "1.1000E-19", "aReallyBigInteger": "1111199999999999999999999999999999999911111" } ]
内容的提问来源于stack exchange,提问作者MatteoDelOmbra
相关产品推荐
相关产品推荐

