例如,{ "number":010 }
被识别为8(因为8个碱基中的010
等于10个碱基中8
)
如果看JsonTextReader.ParseNumber()
,你可以看到
long value2 = text2.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text2, 16) : Convert.ToInt64(text2, 8);
怎么可能禁用基础铸造?也许可以取代JsonTextReader
?
由于JSON标准不允许使用前导零,Newtonsoft似乎决定将JavaScript风格的八进制数解析作为该标准的扩展,请参阅JSON.NET 3.5 Release 7–史上最大版本。这种行为目前被硬编码到JsonTextReader.ParseReadNumber(ReadType readType, char firstChar, int initialPosition)
中,没有强制严格遵守标准的选项(即在前导零上抛出异常),如所述
- 重写Json反序列化一个以零开头的数字作为小数而不是八进制值
- Int解析无法正常工作#1057
- 正在反序列化前导为零的数字#924
- 支持RFC7159解析#646的"严格模式">
作为一种变通方法,您可以使用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为基数的前导零的整数。)
另一种选择是派生自己版本的JsonTextReader
和所有相关的实用程序,并修复JsonTextReader.ParseReadNumber()
的逻辑,以便在nonBase10
为true时抛出JsonReaderException
。不幸的是,派生您自己的JsonTextReader
可能需要大量的持续维护,因为您还需要派生阅读器使用的任何和所有Newtonsoft实用程序(有很多),并将它们更新为原始库中的任何突破性更改。您也可以对请求严格整数解析的增强请求#646进行投票或评论。
Newtonsoft为什么用八进制语法实现数字解析?我的猜测是,他们添加了这个功能来处理整数文本的JavaScript语法中格式化的数字:
整数
整数可以用十进制(以10为基数)、十六进制(以16为基数)或十六进制表示,八进制(基数8)和二进制(基数2)。
- 十进制整数由一系列数字组成,不带前导0(零)
- 整数文字的前导0(零),或者前导0o(或0o)表示它是八进制的。八进制整数只能包含数字0-7
前导0x(或0x)表示十六进制。十六进制整数可以包括数字(0-9)以及字母a-f和a-f。
前导0b(或0b)表示二进制。二进制整数只能包含数字0和1。