将JSON递归反序列化为IDictionary

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

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

如果我指定此类型,例如:

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

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

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

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

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

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

  string json= JsonConvert.SerializeObject(myObject, _jsonSettings) 

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

  var dict = JsonConvert.DeserializeObject>(json, _jsonSettings); 

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

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

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

它是在你派生的JsonConverter ,你在其中放置了如何在json中写入对象的实现。

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

 var o = JsonConvert.DeserializeObject>(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; 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; 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"); } 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: {0}", reader.TokenType)); } } private object ReadArray(JsonReader reader) { IList list = new List(); 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"); } private object ReadObject(JsonReader reader) { var obj = new Dictionary(); 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"); } 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"); } public override bool CanConvert(Type objectType) { return typeof(IDictionary).IsAssignableFrom(objectType); } }