C# Newtonsoft.Json.Linq.JValue 总是返回 Int64

标签 c# .net json dynamic

我正在使用 Newtonsoft.Json 程序集将 Json 字符串反序列化为动态对象 (ExpandoObject)。我遇到的问题是 int 值总是作为 Int64 返回,而我期望的是 Int32。代码如下所示。

namespace Serialization
{
    using System;
    using System.Collections.Generic;
    using System.Dynamic;
    using System.Linq;

    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;

    public static class JsonSerializer
    {
        #region Public Methods

        public static string Serialize(dynamic obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        public static dynamic Deserialize(string s)
        {
            var obj = JsonConvert.DeserializeObject(s);
            return obj is string ? obj as string : Deserialize((JToken)obj);
        }

        #endregion

        #region Methods

        private static dynamic Deserialize(JToken token)
        {
            // FROM : http://blog.petegoo.com/archive/2009/10/27/using-json.net-to-eval-json-into-a-dynamic-variable-in.aspx
            // Ideally in the future Json.Net will support dynamic and this can be eliminated.
            if (token is JValue) return ((JValue)token).Value;
            if (token is JObject)
            {
                var expando = new ExpandoObject();
                (from childToken in token
                 where childToken is JProperty
                 select childToken as JProperty).ToList().
                    ForEach(property => ((IDictionary<string, object>)expando).Add(property.Name, Deserialize(property.Value)));
                return expando;
            }
            if (token is JArray)
            {
                var items = new List<object>();
                foreach (var arrayItem in ((JArray)token)) items.Add(Deserialize(arrayItem));
                return items;
            }
            throw new ArgumentException(string.Format("Unknown token type '{0}'", token.GetType()), "token");
        }

        #endregion
    }
}

通常我不会注意到这一点,但是这个特定的 int 被用于某些类型检查的反射中,但它失败得很惨。任何想法为什么会发生这种情况将不胜感激。

最佳答案

交叉链接回答https://stackoverflow.com/a/9444519/1037948

来自 How do I change the default Type for Numeric deserialization?

释义:

  • 作者有意选择所有 int 返回为 Int64 以避免溢出错误,并且更容易检查(对于 Json.NET 内部,而不是你)
  • 您可以使用自定义转换器来解决这个问题,就像链接答案中发布的那样。

这是一个非常通用的转换器;不完全确定 CanConvert 检查,但对我有用的重要部分是允许 typeof(object):

/// <summary>
/// To address issues with automatic Int64 deserialization -- see https://stackoverflow.com/a/9444519/1037948
/// </summary>
public class JsonInt32Converter : JsonConverter
{
    #region Overrides of JsonConverter

    /// <summary>
    /// Only want to deserialize
    /// </summary>
    public override bool CanWrite { get { return false; } }

    /// <summary>
    /// Placeholder for inheritance -- not called because <see cref="CanWrite"/> returns false
    /// </summary>
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // since CanWrite returns false, we don't need to implement this
        throw new NotImplementedException();
    }

    /// <summary>
    /// Reads the JSON representation of the object.
    /// </summary>
    /// <param name="reader">The <see cref="T:Newtonsoft.Json.JsonReader"/> to read from.</param><param name="objectType">Type of the object.</param><param name="existingValue">The existing value of object being read.</param><param name="serializer">The calling serializer.</param>
    /// <returns>
    /// The object value.
    /// </returns>
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return (reader.TokenType == JsonToken.Integer)
            ? Convert.ToInt32(reader.Value)     // convert to Int32 instead of Int64
            : serializer.Deserialize(reader);   // default to regular deserialization
    }

    /// <summary>
    /// Determines whether this instance can convert the specified object type.
    /// </summary>
    /// <param name="objectType">Type of the object.</param>
    /// <returns>
    /// <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
    /// </returns>
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(Int32) ||
                objectType == typeof(Int64) ||
                // need this last one in case we "weren't given" the type
                // and this will be accounted for by `ReadJson` checking tokentype
                objectType == typeof(object)
            ;
    }

    #endregion
}

关于C# Newtonsoft.Json.Linq.JValue 总是返回 Int64,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8237748/

相关文章:

c# - C# 获取小数点后精确的精度数

c# - 如何处理 KeyRoutedEventArgs e 中 VirtualKey 枚举中的缺失值

javascript - 如何在 JavaScript 中将对象转换为数组?

C# 划分两个二进制数

c# - Context.Request.RawUrl 返回错误的部分编码 url,我该如何解决?

c# - 如何使用 TcpListener/Client 通过 tcp 发送文件? SocketException问题

c# - 绑定(bind)中的 SpecFlow 歧义

c# - asp.net webservices - 如何返回与 "d"相同级别的参数

jquery - 如何获取这个复杂 JSON 对象中的 ISBN_10 标识符

c# - 将日期和时间从 JavaScript 解析为 C#