Json.Net无法正确反序列化带有前导零的数字。
例如,{ "number":010 }识别为8(因为0108底等于810底)
{ "number":010 }
010
8
如果看JsonTextReader.ParseNumber()你可以看到
JsonTextReader.ParseNumber()
long value2 = text2.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text2, 16) : Convert.ToInt64(text2, 8);
如何禁用基本广播?也许可以更换JsonTextReader?
JsonTextReader
由于JSON标准不允许使用前导零,因此Newtonsoft似乎决定实施JavaScript样式的八进制数字解析作为该标准的扩展,请参阅Json.NET 3.5 Release 7 – Everest版本。目前,这种行为已被硬编码为JsonTextReader.ParseReadNumber(ReadType readType, char firstChar, int initialPosition)不可强制严格遵守标准的选项(即在前导零处引发异常),如以下所述:
JsonTextReader.ParseReadNumber(ReadType readType, char firstChar, int initialPosition)
作为一种解决方法,您可以JavaScriptSerializer用来解析为中间动态对象,然后将其重新序列化为中间对象JToken,然后反序列化为JToken最终类:
JavaScriptSerializer
JToken
var json = @"{ ""number"":010 }"; var root = JToken.FromObject(new JavaScriptSerializer().DeserializeObject(json)).ToObject<RootObject>(); if (root.Number != 10) { throw new InvalidOperationException(); }
使用
class RootObject { public int Number { get; set; } }
您也可以重新序列化为中间的JSON字符串,但是JToken对于较大的对象,重新序列化为中间的应该更有效。
(如果您不需要Json.NET的全部功能,请切换到DataContractJsonSerializer或JavaScriptSerializer,也可以选择这样做,因为两者都将以基数10静默地解析一个以零开头的整数。)
DataContractJsonSerializer
另一个选择是派生您自己的版本的JsonTextReader以及所有相关的实用程序,并修复JsonTextReader.ParseReadNumber()抛出JsonReaderExceptionwhen nonBase10为true 的逻辑。不幸的是,JsonTextReader因为您还需要派生阅读器使用的所有Newtonsoft实用程序(有很多),并将它们更新为原始库中的任何重大更改,因此您自己进行分叉可能需要大量的日常维护。您也可以对要求严格的整数解析的增强请求#646投票或发表评论。
JsonTextReader.ParseReadNumber()
JsonReaderException
nonBase10
Newtonsoft为什么要以八进制语法实现数字解析?我的猜测是,他们添加了此功能来处理以JavaScript语法格式表示的整数数字:
整数 整数可以十进制(基数10),十六进制(基数16),八进制(基数8)和二进制(基数2)表示。 十进制整数文字由 不带前导0(零) 的数字序列组成。 整数文字前导0(零),或前导0o(或0O)表示它为八进制。八进制整数只能包含数字0-7。 前导0x(或0X)表示十六进制。十六进制整数可以包含数字(0-9)以及字母af和AF。 前导0b(或0B)表示二进制。二进制整数只能包含0和1的数字。
整数
整数可以十进制(基数10),十六进制(基数16),八进制(基数8)和二进制(基数2)表示。
前导0x(或0X)表示十六进制。十六进制整数可以包含数字(0-9)以及字母af和AF。
前导0b(或0B)表示二进制。二进制整数只能包含0和1的数字。