'JsonConvert.DeserializeObject<Model>( "{float: NaN}" )' 失败



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字符串解析为floatdouble。 但目前情况似乎并非如此。 请参阅序列化 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") 返回类型 FloatJValue,但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();
    }
}

相关内容

  • 没有找到相关文章

最新更新