【问题标题】:Deserialize JSON recursively to IDictionary<string,object> [duplicate]将 JSON 递归反序列化为 IDictionary<string,object> [重复]
【发布时间】:2012-07-18 16:22:33
【问题描述】:

我正在尝试将一些旧作品转换为使用 Newtonsoft JSON.NET。使用System.Web.Script.Serialization.JavaScriptSerializer.Deserialize 方法的默认处理(例如,如果没有指定目标类型)是为内部对象返回Dictionary&lt;string,object&gt;

这实际上是一个非常有用的 JSON 基本类型,因为它也恰好是 ExpandoObjects 使用的底层类型,并且是动态类型最明智的内部实现。

如果我指定这种类型,例如:

 var dict = JsonConvert.DeserializeObject<Dictionary<string,object>>(json);

JSON.NET 将正确反序列化最外层的对象结构,但它会为任何内部结构返回 JObject 类型。我真正需要的是将相同的外部结构用于任何内部对象类型结构。

有没有办法指定用于内部对象的类型,而不仅仅是返回的最外层类型?

【问题讨论】:

    标签: c# json json.net


    【解决方案1】:

    为了让 Json.Net 将 json 字符串反序列化为 IDictionary&lt;string, object&gt;,包括反序列化嵌套对象和数组,您需要创建一个派生自 Json.Net 提供的 JsonConverter 抽象类的自定义类。

    它位于派生的JsonConverter 中,您可以在其中放置对象应如何写入json 和从json 写入的实现。

    您可以像这样使用您的自定义JsonConverter

    var o = JsonConvert.DeserializeObject<IDictionary<string, object>>(json, new DictionaryConverter());
    

    这是我过去成功使用的自定义 JsonConverter,以实现与您在问题中概述的相同目标:

    public class DictionaryConverter : JsonConverter {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { this.WriteValue(writer, value); }
    
        private void WriteValue(JsonWriter writer, object value) {
            var t = JToken.FromObject(value);
            switch (t.Type) {
                case JTokenType.Object:
                    this.WriteObject(writer, value);
                    break;
                case JTokenType.Array:
                    this.WriteArray(writer, value);
                    break;
                default:
                    writer.WriteValue(value);
                    break;
            }
        }
    
        private void WriteObject(JsonWriter writer, object value) {
            writer.WriteStartObject();
            var obj = value as IDictionary<string, object>;
            foreach (var kvp in obj) {
                writer.WritePropertyName(kvp.Key);
                this.WriteValue(writer, kvp.Value);
            }
            writer.WriteEndObject();
        }
    
        private void WriteArray(JsonWriter writer, object value) {
            writer.WriteStartArray();
            var array = value as IEnumerable<object>;
            foreach (var o in array) {
                this.WriteValue(writer, o);
            }
            writer.WriteEndArray();
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
            return ReadValue(reader);
        }
    
        private object ReadValue(JsonReader reader) {
            while (reader.TokenType == JsonToken.Comment) {
                if (!reader.Read()) throw new JsonSerializationException("Unexpected Token when converting IDictionary<string, object>");
            }
    
            switch (reader.TokenType) {
                case JsonToken.StartObject:
                    return ReadObject(reader);
                case JsonToken.StartArray:
                    return this.ReadArray(reader);
                case JsonToken.Integer:
                case JsonToken.Float:
                case JsonToken.String:
                case JsonToken.Boolean:
                case JsonToken.Undefined:
                case JsonToken.Null:
                case JsonToken.Date:
                case JsonToken.Bytes:
                    return reader.Value;
                default:
                    throw new JsonSerializationException
                        (string.Format("Unexpected token when converting IDictionary<string, object>: {0}", reader.TokenType));
            }
        }
    
        private object ReadArray(JsonReader reader) {
            IList<object> list = new List<object>();
    
            while (reader.Read()) {
                switch (reader.TokenType) {
                    case JsonToken.Comment:
                        break;
                    default:
                        var v = ReadValue(reader);
    
                        list.Add(v);
                        break;
                    case JsonToken.EndArray:
                        return list;
                }
            }
    
            throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
        }
    
        private object ReadObject(JsonReader reader) {
            var obj = new Dictionary<string, object>();
    
            while (reader.Read()) {
                switch (reader.TokenType) {
                    case JsonToken.PropertyName:
                        var propertyName = reader.Value.ToString();
    
                        if (!reader.Read()) {
                            throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
                        }
    
                        var v = ReadValue(reader);
    
                        obj[propertyName] = v;
                        break;
                    case JsonToken.Comment:
                        break;
                    case JsonToken.EndObject:
                        return obj;
                }
            }
    
            throw new JsonSerializationException("Unexpected end when reading IDictionary<string, object>");
        }
    
        public override bool CanConvert(Type objectType) { return typeof(IDictionary<string, object>).IsAssignableFrom(objectType); }
    }
    

    【讨论】:

    【解决方案2】:

    使用 Json 反序列化复杂对象时,需要添加 JsonSerializer Settings 作为参数。这将确保所有内部类型都能正确反序列化。

        private JsonSerializerSettings _jsonSettings = new JsonSerializerSettings
        {
            TypeNameHandling = TypeNameHandling.All,
            TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
        };
    

    序列化对象时,可以使用 SerializerSettings:

        string json= JsonConvert.SerializeObject(myObject, _jsonSettings)
    

    然后在反序列化时,使用:

        var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(json, _jsonSettings);
    

    另外,当你序列化时,将 JsonSerializerSettings 添加到你的 SerializeObject(object, settings)

    编辑:如果需要,您还可以更改 TypeNameHandling 和 TypeNameAssemblyFormat。我将它们分别设置为“全部”和“完整”,以确保我的复杂对象毫无疑问地正确序列化和反序列化,但智能感知为您提供其他选择

    【讨论】:

    • @LukePuplett 根据提出的问题,我认为这不正确。
    • 根据问题,这根本不是正确的答案。
    • 是的,这不是正确的答案。下面提到创建 JsonConverter 的答案是 IMO 的最佳答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-10
    • 2011-08-20
    • 2018-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多