Newtonsoft的 Json.Net 显然能够反序列化NaN,但我似乎无法强迫它将其反序列化到提供的浮点字段中。我得到了一个Unexpected character "N"
例外。
在下面的代码中:
using Newtonsoft.Json;
namespace TestNanDeserialize
{
public class Number
{
public float Float;
}
public class Empty
{
}
internal class Program
{
private const string testJson = "{float: NaN}";
private static void Main(string[] args)
{
Succeeds();
Fails();
}
private static void Succeeds()
{
var result = JsonConvert.DeserializeObject<Empty>(testJson);
}
private static void Fails()
{
var result = JsonConvert.DeserializeObject<Number>(testJson);
}
}
}
Succeeds()
和 Fails()
生成两个非常不同的调用堆栈:
Succeeds()
Newtonsoft.Json.dll!Newtonsoft.Json.JsonTextReader.ParseNumberNaN() Line 2299 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonTextReader.ParseValue() Line 1572 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonTextReader.Read() Line 381 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(object newObject, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, string id) Line 2331 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, object existingValue) Line 485 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, object existingValue) Line 291 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(Newtonsoft.Json.JsonReader reader, System.Type objectType, bool checkAdditionalContent) Line 167 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonSerializer.DeserializeInternal(Newtonsoft.Json.JsonReader reader, System.Type objectType) Line 823 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonSerializer.Deserialize(Newtonsoft.Json.JsonReader reader, System.Type objectType) Line 802 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonConvert.DeserializeObject(string value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) Line 863 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonConvert.DeserializeObject<TestNanDeserialize.Empty>(string value, Newtonsoft.Json.JsonSerializerSettings settings) Line 820 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonConvert.DeserializeObject<TestNanDeserialize.Empty>(string value) Line 757 C#
TestNanDeserialize.exe!TestNanDeserialize.Program.Succeeds() Line 26 C#
TestNanDeserialize.exe!TestNanDeserialize.Program.Main(string[] args) Line 20 C#
Fails()
Newtonsoft.Json.dll!Newtonsoft.Json.JsonTextReader.ReadAsDouble() Line 948 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonContract contract, bool hasConverter) Line 2214 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(object newObject, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, string id) Line 2359 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, object existingValue) Line 485 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, object existingValue) Line 291 C#
Newtonsoft.Json.dll!Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(Newtonsoft.Json.JsonReader reader, System.Type objectType, bool checkAdditionalContent) Line 167 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonSerializer.DeserializeInternal(Newtonsoft.Json.JsonReader reader, System.Type objectType) Line 823 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonSerializer.Deserialize(Newtonsoft.Json.JsonReader reader, System.Type objectType) Line 802 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonConvert.DeserializeObject(string value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) Line 863 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonConvert.DeserializeObject<TestNanDeserialize.Number>(string value, Newtonsoft.Json.JsonSerializerSettings settings) Line 820 C#
Newtonsoft.Json.dll!Newtonsoft.Json.JsonConvert.DeserializeObject<TestNanDeserialize.Number>(string value) Line 757 C#
TestNanDeserialize.exe!TestNanDeserialize.Program.Fails() Line 31 C#
TestNanDeserialize.exe!TestNanDeserialize.Program.Main(string[] args) Line 21 C#
您可能认为这应该足以调试它,也许它应该,但它实际上对我来说并不明显,在所有这些层中应该以不同的方式发生哪些分叉以使其工作。
编辑:是的,我知道未引用的NaN不是有效的JSON。Json.Net 的一个声明功能是对 NaN 的支持。它显然能够反序列化它,如上面的代码所示。但是,我不确定它是否可以反序列化为浮点字段。
注意:我已经在以下位置打开了一个缺陷:https://github.com/JamesNK/Newtonsoft.Json/issues/908
困难的原因是您的 JSON 无效 - 特别是需要引号的符号NaN
。 即,可以将以下 JSON 反序列化为Number
类:
{"float": "NaN"}
以下不能:
{float: NaN}
请注意,有一个设置,FloatFormatHandling.Symbol
,允许在没有引号的情况下输出NaN
,因此可能是早期版本的 Json.NET 能够将不带引号的NaN
字符串解析为float
或double
。 但目前情况似乎并非如此。 请参阅序列化 NaN 结果生成不符合 JSON 的文本 Json.NET 以及 5.0 第 1 版:序列化 NaN 和无穷大浮点值。
更新 2
我尝试在各种版本的 Json.NET 中反序列化未带引号的 JSON 字符串{float: NaN}
:
- 8.0.2(当前):失败。
- 7.0.1:成功。
- 3.5:成功。
所以这可能是一种回归。 您可能需要报告问题。
更新
正如@shannon所指出的,Json.NET对JSON标准的扩展存在不一致。 JToken.Parse("NaN")
返回类型 Float
的JValue
,但JsonConvert.DeserializeObject<double>("NaN")
引发异常。 可以使用这种不一致来编写处理非引号NaN
字符串的转换器:
public class FloatNanConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(float) || objectType == typeof(float?);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var value = JValue.Load(reader);
if (objectType == typeof(float?))
return (float?)value;
else
return (float)value;
}
public override bool CanWrite { get { false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}