.NET Framework 4.6.1中JSON反序列化前导零问题的解决方法
问题场景
我使用以下代码反序列化JSON请求:
dynamic obj = JsonConvert.DeserializeObject(telegram.ReceiveTelegram);
当JSON请求为{"Task":{...,"PosX":2278,"PosY":6500,...}}时无问题,但当请求包含前导零的数字(如{"Task":{...,"PosX":02278,"PosY":06500,...}})时,抛出异常:
Newtonsoft.Json.JsonReaderException: Input string '02278' is not a valid number. Path 'State.PosX', line 1, position 385. ---> System.FormatException: Additional non-parsable characters are at the end of the string.
at System.ParseNumbers.StringToLong(String s, Int32 radix, Int32 flags, Int32* currPos)
at System.Convert.ToInt64(String value, Int32 fromBase)
at Newtonsoft.Json.JsonTextReader.ParseReadNumber(ReadType readType, Char firstChar, Int32 initialPosition)
应用基于.NET Framework 4.6.1,需解决该反序列化异常。
解决方案
方法1:配置序列化设置允许前导零
如果使用的Newtonsoft.Json版本支持AllowLeadingZeroes属性(通常版本≥12.0.1支持),可直接通过配置解决:
var settings = new JsonSerializerSettings { AllowLeadingZeroes = true }; dynamic obj = JsonConvert.DeserializeObject(telegram.ReceiveTelegram, settings);
若版本较低没有该属性,可配合FloatParseHandling设置兼容:
var settings = new JsonSerializerSettings { FloatParseHandling = FloatParseHandling.Decimal }; dynamic obj = JsonConvert.DeserializeObject(telegram.ReceiveTelegram, settings);
方法2:自定义JsonConverter处理带前导零的整数
创建自定义转换器,统一解析带前导零的数字:
public class LeadingZeroIntegerConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(int) || objectType == typeof(long) || objectType == typeof(int?) || objectType == typeof(long?); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.String) { string value = reader.Value.ToString(); // 去除前导零,空值则设为0 string trimmed = string.IsNullOrEmpty(value.TrimStart('0')) ? "0" : value.TrimStart('0'); return objectType == typeof(int) || objectType == typeof(int?) ? int.Parse(trimmed) : long.Parse(trimmed); } return reader.TokenType == JsonToken.Integer ? reader.Value : null; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { writer.WriteValue(value); } }
使用转换器反序列化:
var settings = new JsonSerializerSettings(); settings.Converters.Add(new LeadingZeroIntegerConverter()); dynamic obj = JsonConvert.DeserializeObject(telegram.ReceiveTelegram, settings);
方法3:预处理JSON字符串(临时方案)
若无法修改序列化配置,可先通过正则将带前导零的数字转为字符串,再反序列化:
// 正则匹配键值对中带前导零的数字,替换为字符串格式 string processedJson = Regex.Replace(telegram.ReceiveTelegram, @"(""[^""]+""):0(\d+)", @"$1:""0$2"""); dynamic obj = JsonConvert.DeserializeObject(processedJson);
注意:此方法需根据实际JSON结构调整正则表达式,避免误匹配合法内容。
内容的提问来源于stack exchange,提问作者Dominique

