我有以下测试代码:

[TestClass]
public class TestJsonDeserialize
{
    public class MyClass
    {
        [JsonProperty("myint")]
        public int MyInt { get; set; }
        [JsonProperty("Mybool")]
        public bool Mybool { get; set; }
    }

    [TestMethod]
    public void Test1()
    {
        var errors = new List<string>();
        var json1 = "{\"myint\":1554860000,\"Mybool\":false}";
        var json2 = "{\"myint\":3554860000,\"Mybool\":false}";
        var i = JsonConvert.DeserializeObject<MyClass>(json2, new JsonSerializerSettings
        {
            Error = delegate (object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
            {
                Debug.WriteLine(args.ErrorContext.Error.Message);
                errors.Add(args.ErrorContext.Error.Message);
                args.ErrorContext.Handled = true;
            }
        });
        Assert.IsTrue(errors.Count <= 1);
    }
}

调用JsonConvert.DeserializeObject会产生2个错误。其中一个是预期的,但另一个不是。
错误是:
  • JSON整数3554860000对于Int32而言太大或太小。路径“myint”,第1行,位置19。
  • 反序列化对象时出现意外 token : bool 值。路径“Mybool”,第1行,位置34。

  • 尽管第一个错误被标记为已处理,但为什么会有第二个错误。
    我已经从Newtonsoft.Json 8.0.2更新到9.0.1,但是它仍然存在。
    当传递第一个字符串(用json1而不是json2)时,则根本不会发生任何错误。

    最佳答案

    更新

    报告为Issue 1194: JsonTextReader.ParseNumber leads to error after ThrowReaderError并被Newtonsoft封闭,因为在当前版本中不可复制,该版本随后以Json.NET 10.0.1的形式发布。

    原始答案

    这可能是 JsonTextReader 中的错误。

    JsonTextReader.ParseNumber(ReadType readType, char firstChar, int initialPosition) 中,有以下逻辑,有些简化了:

    else if (readType == ReadType.ReadAsInt32)
    {
    
    // Snip
    
            int value;
            ParseResult parseResult = ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value);
            if (parseResult == ParseResult.Success)
            {
                numberValue = value;
            }
            else if (parseResult == ParseResult.Overflow)
            {
                throw ThrowReaderError("JSON integer {0} is too large or small for an Int32.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
            }
            else
            {
                throw ThrowReaderError("Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
            }
        }
    
        numberType = JsonToken.Integer;
    }
    
    // Snip
    // Finally, after successfully parsing the number
    
    ClearRecentString();
    
    // index has already been updated
    SetToken(numberType, numberValue, false);
    

    此时,ThrowReadError()引发异常,流位置已超前过大的整数。但是, JsonReader.TokenType 的值尚未更新,仍然为成功解析的最后一个 token (即JsonToken.PropertyName名称)返回 "myint" 。稍后,在吞下并忽略了异常之后,流位置和当前 token 值之间的不一致会导致"Mybool"属性名称被跳过,从而导致第二个错误。

    如果在调试器中引发异常时,我手动调用
    SetToken(JsonToken.Undefined);
    ClearRecentString();
    

    然后,文件的其余部分可以成功解析。 (我不确定JsonToken.Undefined在这里是正确的选择。)

    您可能需要report an issue到Newtonsoft。

    由于JsonReader没有传递给错误处理程序,因此,我能找到的唯一解决方法是将JsonTextReader子类化,如下所示:
    public class FixedJsonTextReader : JsonTextReader
    {
        public FixedJsonTextReader(TextReader reader) : base(reader) { }
    
        public override int? ReadAsInt32()
        {
            try
            {
                return base.ReadAsInt32();
            }
            catch (JsonReaderException)
            {
                if (TokenType == JsonToken.PropertyName)
                    SetToken(JsonToken.None);
                throw;
            }
        }
    }
    

    然后执行:
    var errors = new List<string>();
    var json2 = "{\"myint\":3554860000,\"Mybool\":false}";
    
    using (var reader = new FixedJsonTextReader(new StringReader(json2)))
    {
        var settings = new JsonSerializerSettings
        {
            Error = delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args)
            {
                Debug.WriteLine(args.ErrorContext.Error.Message);
                errors.Add(args.ErrorContext.Error.Message);
                args.ErrorContext.Handled = true;
            }
        };
        var i = JsonSerializer.CreateDefault(settings).Deserialize<MyClass>(reader);
    }
    Assert.IsTrue(errors.Count <= 1); // Passes
    

    关于c# - 在JsonConvert.DeserializeObject中反序列化对象时出现意外 token ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41935806/

    10-14 11:45