Json.Net无法使用前导零正确反序列化数字。
例如{ "number":010 }
被识别为8(因为{基础中的010
等于10基础中的8
如果查看JsonTextReader.ParseNumber()
,您可以看到
long value2 = text2.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text2, 16) : Convert.ToInt64(text2, 8);
如何禁用base-cast?也许可以替换JsonTextReader
?
答案 0 :(得分:4)
由于JSON standard不允许前导零,因此看起来Newtonsoft决定实现JavaScript样式八进制数的解析作为标准的扩展,请参阅Json.NET 3.5 Release 7 – Biggest Release Ever Edition。此行为目前已硬编码到JsonTextReader.ParseReadNumber(ReadType readType, char firstChar, int initialPosition)
,没有强制严格遵守标准的选项(即在前导零点上抛出异常),如下所述:
作为一种变通方法,您可以使用JavaScriptSerializer
解析为中间动态对象,然后将其重新序列化为中间JToken
,然后将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的前导零的整数。)< / p>
另一种选择是分叉您自己的JsonTextReader
版本和所有相关的实用程序,并修复JsonTextReader.ParseReadNumber()
的逻辑,以便在JsonReaderException
为真时抛出nonBase10
。不幸的是,分支您自己的JsonTextReader
可能需要大量的持续维护,因为您还需要分叉读取器使用的任何和所有Newtonsoft实用程序(有很多)并将它们更新为原始库中的任何重大更改。您还可以对请求严格整数解析的enhancement request #646进行投票或评论。
为什么Newtonsoft用八进制语法实现数字解析?我的猜测是,他们添加了此功能来处理JavaScript syntax for integer literals中格式化的数字:
<强>整数强>
整数可以用十进制(基数10),十六进制(基数16)表示, 八进制(基数为8)和二进制(基数为2)。
- 十进制整数文字由一系列数字组成,不带前导0(零)。
- 在整数文字上前导0(零),或者前导0o(或0O)表示它是八进制。八进制整数只能包含数字 0-7。
前导0x(或0X)表示十六进制。十六进制整数可以包括数字(0-9)和字母a-f和A-F.
前导0b(或0B)表示二进制。二进制整数可以包括仅0和1的数字。