覆盖 Json 反序列化带有前导零的数字作为十进制而不是八进制值
Override Json deserializing a number with a leading zero as a decimal and not an octal value
我正在生成一个 json 对象,
{
"number":0100
}
当此对象在 C# 中使用 Newtonsoft.Json 反序列化时,0100 由于前导零而被视为八进制数。
有没有办法覆盖此功能并使其将数字视为十进制整数?
如果 Newtonsoft.Json 那样做,那就是一个错误。根据 http://json.org 上记录的 JSON 语法:
"A number is very much like a C or Java number, except that the octal and hexadecimal formats are not used."
并且语法图不允许数字有一个前导的非重要零。
RFC 4627 第 2.4 节。同意:
"Octal and hex forms are not allowed. Leading zeros are not allowed."
所以实际上,根据 RFC,您对前导零的使用根本无效 JSON ...。
所以,回答你的问题:
Is there a way to override this functionality and make it consider the number as a decimal integer?
可能不会。而且,你不应该这样做。相反,您应该修复 JSON,或者向生成它的人抱怨它不符合要求。
您还应该将此报告为 Newtonsoft.Json. 中的错误。不要打扰。作者不承认这是一个错误。我建议切换到正确实现 JSON 规范的 JSON 库。
给JSON实施者的建议
JSON 规范(两个版本)明确指出不允许使用十六进制和八进制形式。
如果您将对十六进制 and/or 八进制(或其他一些非官方 "extension")的支持添加到您的 JSON 解析器,您将添加到 JSON 的碎片中标准。这很糟糕。
这也是一个坏主意,因为当不重要的前导零被视为八进制标记时,许多最终用户会感到惊讶。这导致了这样的问题......(我猜)OP 的最终用户已经被烧毁,并要求他修复 >>his<< 代码以处理前导零 "properly".
此处的正确行为是 严格 实施 JSON 规范,并拒绝任何带有不重要前导零的数字。 (就个人而言,我会为此和“0x...”十六进制形式实现特殊情况的错误消息。)
我看过 JsonTextReader.ParseNumber()
(发生 "magic" 数字读取的方法)。我会说这是不可行的。八进制大小写特别处理
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
我正在生成一个 json 对象,
{
"number":0100
}
当此对象在 C# 中使用 Newtonsoft.Json 反序列化时,0100 由于前导零而被视为八进制数。 有没有办法覆盖此功能并使其将数字视为十进制整数?
如果 Newtonsoft.Json 那样做,那就是一个错误。根据 http://json.org 上记录的 JSON 语法:
"A number is very much like a C or Java number, except that the octal and hexadecimal formats are not used."
并且语法图不允许数字有一个前导的非重要零。
RFC 4627 第 2.4 节。同意:
"Octal and hex forms are not allowed. Leading zeros are not allowed."
所以实际上,根据 RFC,您对前导零的使用根本无效 JSON ...。
所以,回答你的问题:
Is there a way to override this functionality and make it consider the number as a decimal integer?
可能不会。而且,你不应该这样做。相反,您应该修复 JSON,或者向生成它的人抱怨它不符合要求。
您还应该将此报告为 Newtonsoft.Json. 中的错误。不要打扰。作者不承认这是一个错误。我建议切换到正确实现 JSON 规范的 JSON 库。
给JSON实施者的建议
JSON 规范(两个版本)明确指出不允许使用十六进制和八进制形式。
如果您将对十六进制 and/or 八进制(或其他一些非官方 "extension")的支持添加到您的 JSON 解析器,您将添加到 JSON 的碎片中标准。这很糟糕。
这也是一个坏主意,因为当不重要的前导零被视为八进制标记时,许多最终用户会感到惊讶。这导致了这样的问题......(我猜)OP 的最终用户已经被烧毁,并要求他修复 >>his<< 代码以处理前导零 "properly".
此处的正确行为是 严格 实施 JSON 规范,并拒绝任何带有不重要前导零的数字。 (就个人而言,我会为此和“0x...”十六进制形式实现特殊情况的错误消息。)
我看过 JsonTextReader.ParseNumber()
(发生 "magic" 数字读取的方法)。我会说这是不可行的。八进制大小写特别处理
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