【问题标题】:`JsonConvert.DeserializeObject<Model>("{float: NaN}")` fails`JsonConvert.DeserializeObject<Model>("{float: NaN}")` 失败
【发布时间】:2016-05-15 05:15:16
【问题描述】:

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

【问题讨论】:

  • “Newtonsoft 的 Json.Net 显然能够反序列化 NaN”。我不会这么认为。 NaN 不是 JSON 规范的一部分。因此,您发布的示例实际上不是有效的 JSON。
  • @Andrew:我知道它不是有效的 JSON。然而它经常被使用。您的评论与我关于 Json.Net 显然能够做到这一点的声明无关,我什么也没做。我的陈述是基于事实的,正如我上面提供的代码所示。谢谢。

标签: json.net


【解决方案1】:

您遇到困难的原因是您的JSON is invalid -- 特别是符号NaN 需要引用。 IE。以下 JSON 可以反序列化到您的 Number 类中:

{"float": "NaN"}

以下不能:

{float: NaN}

请注意,有一个设置 FloatFormatHandling.Symbol 允许在不带引号的情况下输出 NaN,因此可能是早期版本的 Json.NET 能够将不带引号的 NaN 字符串解析为 floatdouble。但目前情况似乎并非如此。请参阅Serializing NaN results in non-JSON compliant textJson.NET 5.0 Release 1: Serializing NaN and Infinity Floating Point Values

更新 2

我尝试在各种版本的 Json.NET 中反序列化不带引号的 JSON 字符串 {float: NaN}

  • 8.0.2(当前):失败。
  • 7.0.1:成功。
  • 3.5:成功。

所以这可能是一种回归。你可能想report an issue

更新

正如@shannon 所指出的,Json.NET 对 JSON 标准的扩展存在不一致。 JToken.Parse("NaN") 返回 JValue 类型的 Float,但 JsonConvert.DeserializeObject&lt;double&gt;("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();
    }
}

【讨论】:

  • 太好了,谢谢。有趣的是,它可以毫无问题地反序列化为匿名类型。
  • 另外,仅供参考,非常清楚 NaN 不是有效的 JSON。这是否是“问题”是一个观点问题。
  • OTOH,如果您考虑一下,将引用的 "NaN" 反序列化为匿名类型将不得不产生一个字符串。所以这是“必需的”或“对称的”(如果你愿意的话)功能。
  • @shannon 我会说问题是 JSON.NET 会输出无效的 JSON,然后它不能用相同的设置反序列化它。
  • @FINDarkside:我有点同意。我希望有一个强大的产品来输出有效的格式,但仍然接受无效但常用的格式(就像 NaN 一样)。我怀疑这个产品打算这样做,但正如 dbc 建议的那样,它只是显示出回归。
猜你喜欢
  • 2018-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多