覆盖 Json 反序列化将前导零作为小数而不是八进制值的数字



我正在生成一个 json 对象,

{
   "number":0100
}

当此对象使用 Newtonsoft.JSON 在 C# 中反序列化时,由于前导零,0100 被视为八进制数。有没有办法覆盖此功能并使其将数字视为十进制整数?

如果Newtonsoft.Json这样做,那么这是一个错误。 根据 http://json.org 上记录的 JSON 语法:

"数字非常像C或Java数字,只是不使用八进制和十六进制格式

并且语法图不允许数字具有前导非有效零。

RFC 4627 第 2.4 节同意:

"不允许使用

八进制和十六进制形式。 不允许使用前导零。

所以事实上,您使用前导零根本不是有效的 JSON......根据RFC。


所以,回答你的问题:

有没有办法覆盖此功能并使其将数字视为十进制整数?

应该不会。 而且,你不应该这样做。 相反,您应该修复 JSON,或者向生成它的人抱怨它不符合要求。

您还应该将其报告为Newtonsoft.Json中的错误。 不要打扰。 作者不承认这是一个错误。 我建议切换到正确实现 JSON 规范的 JSON 库。


给 JSON 实现者的建议

JSON规范(两个版本)明确指出不允许十六进制和八进制形式。

如果向 JSON

解析器添加对十六进制和/或八进制(或其他一些非官方"扩展")的支持,则会增加 JSON 标准的碎片。 这很糟糕。

这也是一个坏主意,因为当将不重要的前导零视为八进制标记时,许多最终用户会感到惊讶。 这导致了这样的问题...(我猜)OP 的最终用户已被烧毁,并要求他修复>>他的<<代码以"正确"处理前导零。

这里的正确行为是严格执行 JSON 规范,并拒绝任何具有不重要前导零的数字。 (就个人而言,我会为此和"0x..."十六进制形式实现特殊情况错误消息。

我看过JsonTextReader.ParseNumber()(数字读取的"魔力"发生的方法)。我会说这是不可行的。八进制案件特别处理

bool flag2 = c == '0' ...

然后

long value2 = text2.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? 
                  Convert.ToInt64(text2, 16) : 
                  Convert.ToInt64(text2, 8); // Here OCTAL!!!

我还没有找到任何方法来覆盖此方法(除了重写所有在 Json 解析中执行所有操作Read() 方法)

你的.net框架是什么?
可以使用 DataContractJsonSerializer 对象来反序列化该 json。
我试过了。成功了。
在 .net 3.5 中:它位于 System.ServiceMode.Web 程序集中。
使用 .net 4+:它位于 System.Runtime.Serialization.Json 程序集中。

例:

[DataContract]
public class TestObject
{
    private int _id;
    private string _name;
    private decimal _number;
    [DataMember]
    public int ID
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
        }
    }
    [DataMember]
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }
    [DataMember]
    public decimal Number
    {
        get
        {
            return _number;
        }
        set
        {
            _number = value;
        }
    }
}

测试

private string jsonText = "{"Id": 1, "Name": "kanozuki", "Number":"0100"}";
TestObject obj = Deserialise<TestObject>(jsonText);
public T Deserialise<T>(string json)
    {
        DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
        using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
        {
            T result = (T)deserializer.ReadObject(stream);
            return result;
        }
    }

结果 obj.Id:1 obj.Name:kanozuki obj.Number:100

最新更新