json 净前导零(禁用基数转换)

dar*_*hac 4 c# json json.net

Json.Net 无法正确反序列化带有前导零的数字。

例如{ "number":010 }识别为 8(因为0108 基等于810 基)

如果看JsonTextReader.ParseNumber()你可以看到

long value2 = text2.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text2, 16) : Convert.ToInt64(text2, 8);
Run Code Online (Sandbox Code Playgroud)

怎么可能禁用 base-cast?也许可以更换JsonTextReader

dbc*_*dbc 5

由于JSON 标准不允许使用前导零,因此 Newtonsoft 似乎决定实现 JavaScript 风格的八进制数的解析作为标准的扩展,请参阅Json.NET 3.5 第 7 版 – 有史以来最大的版本。这种行为目前是硬编码的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();
}
Run Code Online (Sandbox Code Playgroud)

使用

class RootObject
{
    public int Number { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

您也可以重新序列化为中间 JSON 字符串,但重新序列化为中间体JToken对于较大的对象应该更有效。

(如果您不需要 Json.NET 的全部功能,则切换到DataContractJsonSerializerJavaScriptSerializer也是选项,因为两者都会默默地解析一个以 10 为基数的前导零的整数。)

另一种选择是分叉您自己的版本JsonTextReader和所有相关实用程序,并修复JsonTextReader.ParseReadNumber()抛出JsonReaderExceptionwhennonBase10为真的逻辑。不幸的是,分叉你自己的JsonTextReader可能需要大量的持续维护,因为你还需要分叉读者使用的任何和所有 Newtonsoft 实用程序(有很多),并将它们更新为原始库中的任何重大更改。您还可以对要求严格整数解析的增强请求 #646 进行投票或评论。

为什么 Newtonsoft 用八进制语法实现数字解析?我的猜测是他们添加了这个功能来处理整数文字JavaScript 语法格式的数字:

整数

整数可以用十进制(基数 10)、十六进制(基数 16)、八进制(基数 8)和二进制(基数 2)表示。

  • 十进制整数文字由没有前导 0(零)的数字序列组成。
  • 整数文字的前导 0(零),或前导 0o(或 0O)表示它是八进制的。八进制整数只能包含数字 0-7。
  • 前导 0x(或 0X)表示十六进制。十六进制整数可以包括数字 (0-9) 和字母 af 和 A​​F。

  • 前导 0b(或 0B)表示二进制。二进制整数只能包含数字 0 和 1。

  • 呃……“技术上”不允许?我会走得更远。如果您希望将它们解释为十进制,那么它们从根本上来说是有缺陷的,它们甚至不会像 JavaScript 中那样进行评估。 (2认同)