Since leading zeros are disallowed by the the JSON standard, it would seem Newtonsoft decided to implement parsing of JavaScript-style octal numbers as an extension to the standard, see Json.NET 3.5 Release 7 – Biggest Release Ever Edition. This behavior is currently hardcoded into JsonTextReader.ParseReadNumber(ReadType readType, char firstChar, int initialPosition)
with no option to force strict conformance to the standard (i.e. throw an exception on a leading zero), as is stated in:
As a workaround, you could use JavaScriptSerializer
to parse to an intermediate dynamic object, then re-serialize that to an intermediate JToken
, then deserialize that JToken
to your final class:
var json = @"{ ""number"":010 }";
var root = JToken.FromObject(new JavaScriptSerializer().DeserializeObject(json)).ToObject<RootObject>();
if (root.Number != 10)
{
throw new InvalidOperationException();
}
Using
class RootObject
{
public int Number { get; set; }
}
You could also re-serialize to an intermediate JSON string, but re-serializing to an intermediate JToken
should be more efficient for larger objects.
(Switching to DataContractJsonSerializer
or JavaScriptSerializer
are also options if you do not need the full functionality of Json.NET, since both will silently parse an integer with a leading zero in base 10.)
Another option would be to fork your own version of JsonTextReader
and all associated utilities, and fix the logic of JsonTextReader.ParseReadNumber()
to throw a JsonReaderException
when nonBase10
is true. Unfortunately, forking your own JsonTextReader
may require substantial ongoing maintenance, since you will also need to fork any and all Newtonsoft utilities used by the reader (there are many) and update them to any breaking changes in the original library. You could also vote up or comment on enhancement request #646 requesting strict integer parsing.
Why did Newtonsoft implement parsing of numbers in octal syntax? My speculation is that they added this functionality to handle numbers formatted in the JavaScript syntax for integer literals:
Integers
Integers can be expressed in decimal (base 10), hexadecimal (base 16),
octal (base 8) and binary (base 2).
- Decimal integer literal consists of a sequence of digits without a leading 0 (zero).
- Leading 0 (zero) on an integer literal, or leading 0o (or 0O) indicates it is in octal. Octal integers can include only the digits
0-7.
Leading 0x (or 0X) indicates hexadecimal. Hexadecimal integers can include digits (0-9) and the letters a-f and A-F.
Leading 0b (or 0B) indicates binary. Binary integers can include digits only 0 and 1.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…