将JSON递归地反序列化到IDictionary [duplicate]

时间:2021-07-06 19:01:52

This question already has an answer here:

这个问题已经有了答案:

I'm trying to convert some older work to use Newtonsoft JSON.NET. The default handling using the System.Web.Script.Serialization.JavaScriptSerializer.Deserialize method (e.g. if no target type is specified) is to return a Dictionary<string,object> for inner objects.

我正在尝试将一些旧的工作转换为使用Newtonsoft JSON.NET。使用system . web . script. serializ.javascriptserializer的默认处理。反序列化方法(例如,如果没有指定目标类型)是返回一个字典 用于内部对象。 ,object>

This is actually a really useful basic type for JSON since it also happens to be the underlying type used by ExpandoObjects and is the most sensible internal implementation for dynamic types.

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

If I specify this type, e.g.:

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

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

JSON.NET will deserialize the outermost object structure correctly, but it returns a JObject type for any inner structures. What I really need is for the same outer structure to be used for any inner object-type structures.

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

Is there a way to specify a type to be used for inner objects, and not just the outermost type returned?

是否有一种方法可以指定用于内部对象的类型,而不只是返回的最外层类型?

2 个解决方案

#1


7  

When Deserializing your complex objects using Json, you need to add a JsonSerializer Settings as a parameter. This will ensure that all of the inner types get deserialized properly.

当使用Json反序列化您的复杂对象时,您需要添加一个JsonSerializer设置作为参数。这将确保所有的内部类型都得到正确的反序列化。

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

When Serializing your object, you can use the SerializerSettings:

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

    string json= JsonConvert.SerializeObject(myObject, _jsonSettings)

Then when you are deserializing, use:

当你反序列化时,使用:

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

Also, when you serialize, add the JsonSerializerSettings to your SerializeObject(object, settings)

此外,在序列化时,将JsonSerializerSettings添加到SerializeObject(对象、设置)

Edit: You can also change the TypeNameHandling and TypeNameAssemblyFormat if you need to. I have them set at 'All' and 'Full' respectively to ensure that my complex objects get serialized and deserialized properly without doubt, but intellisense provides you with other alternatives

编辑:如果需要的话,您还可以更改TypeNameHandling和typename汇编格式。我将它们分别设置为“All”和“Full”,以确保我的复杂对象毫无疑问地得到序列化和反序列化,但是intellisense为您提供了其他选择。

#2


15  

In order to get Json.Net to deserialize a json string into an IDictionary<string, object> including deserializing nested objects and arrays you will need to create a custom class that derives from the JsonConverter abstract class provided by Json.Net.

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

It is in your derived JsonConverter where you put the implementation of how an object should be written to and from json.

它是在您的派生JsonConverter中,您将如何将对象写入和从json写入的实现。

You can use your custom JsonConverter like this:

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

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

Here is a custom JsonConverter I have used with success in the past to achieve the same goals as you outline in your question:

这里有一个自定义的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); }
}

#1


7  

When Deserializing your complex objects using Json, you need to add a JsonSerializer Settings as a parameter. This will ensure that all of the inner types get deserialized properly.

当使用Json反序列化您的复杂对象时,您需要添加一个JsonSerializer设置作为参数。这将确保所有的内部类型都得到正确的反序列化。

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

When Serializing your object, you can use the SerializerSettings:

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

    string json= JsonConvert.SerializeObject(myObject, _jsonSettings)

Then when you are deserializing, use:

当你反序列化时,使用:

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

Also, when you serialize, add the JsonSerializerSettings to your SerializeObject(object, settings)

此外,在序列化时,将JsonSerializerSettings添加到SerializeObject(对象、设置)

Edit: You can also change the TypeNameHandling and TypeNameAssemblyFormat if you need to. I have them set at 'All' and 'Full' respectively to ensure that my complex objects get serialized and deserialized properly without doubt, but intellisense provides you with other alternatives

编辑:如果需要的话,您还可以更改TypeNameHandling和typename汇编格式。我将它们分别设置为“All”和“Full”,以确保我的复杂对象毫无疑问地得到序列化和反序列化,但是intellisense为您提供了其他选择。

#2


15  

In order to get Json.Net to deserialize a json string into an IDictionary<string, object> including deserializing nested objects and arrays you will need to create a custom class that derives from the JsonConverter abstract class provided by Json.Net.

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

It is in your derived JsonConverter where you put the implementation of how an object should be written to and from json.

它是在您的派生JsonConverter中,您将如何将对象写入和从json写入的实现。

You can use your custom JsonConverter like this:

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

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

Here is a custom JsonConverter I have used with success in the past to achieve the same goals as you outline in your question:

这里有一个自定义的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); }
}