我正在使用 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/