我正在使用Newtonsoft.Json程序集将Json字符串反序列化为动态对象(ExpandoObject)。我遇到的问题是int值始终以我期望的Int32形式返回为Int64。该代码可以在下面看到。
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被用于某种类型检查的反映,并且失败了。任何想法为什么会发生这种情况将不胜感激。
释义:
Int64
这是一个真正的通用转换器;不能完全确定CanConvert支票,但对我有用的重要部分是允许typeof(object):
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 }