json net leading zeros(禁用base-cast)

时间:2016-06-01 07:01:20

标签: c# json json.net

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

1 个答案:

答案 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的全部功能,也可以选择切换到DataContractJsonSerializerJavaScriptSerializer,因为两者都将静默解析基数为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的数字。

  •