2012-07-19 13 views
14

Estoy tratando de convertir algunos trabajos más antiguos para usar Newtonsoft JSON.NET. El manejo predeterminado utilizando el método System.Web.Script.Serialization.JavaScriptSerializer.Deserialize (por ejemplo, si no se especifica ningún tipo de destino) es devolver un Dictionary<string,object> para objetos internos.Deserializar JSON recursivamente a IDictionary <cadena, objeto>

Este es realmente un tipo básico realmente útil para JSON ya que también es el tipo subyacente utilizado por ExpandoObjects y es la implementación interna más sensata para los tipos dinámicos.

Si especifico este tipo, por ejemplo .:

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

JSON.NET será deserializar la estructura del objeto más externa correctamente, pero devuelve un tipo de JObject para cualquier estructuras internas. Lo que realmente necesito es que se use la misma estructura externa para cualquier estructura interna de tipo objeto.

¿Hay alguna manera de especificar un tipo que se utilizará para objetos internos, y no solo el tipo más externo devuelto?

Respuesta

7

Al deserializar sus objetos complejos usando Json, debe agregar una configuración de JsonSerializer como parámetro. Esto asegurará que todos los tipos internos se deserializan correctamente.

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

al serializar el objeto, puede utilizar los SerializerSettings:

string json= JsonConvert.SerializeObject(myObject, _jsonSettings) 

Entonces, cuando usted está deserializar, utilice:

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

Además, al serializar, añadir los JsonSerializerSettings a su SerializeObject (objeto, configuración)

Editar: También puede cambiar t he TypeNameHandling y TypeNameAssemblyFormat si es necesario. Los configuré en 'Todos' y 'Completo' respectivamente para asegurar que mis objetos complejos se serializan y deserializan correctamente, sin duda, pero intellisense le ofrece otras alternativas

+0

¿Es esta la respuesta correcta? –

+1

@LukePuplett No creo que esto sea correcto, basado en la pregunta hecha. –

+0

Basado en la pregunta, esta no es la respuesta correcta. –

15

Para lograr que Json.Net deserialice una cadena json en un IDictionary<string, object> que incluye la deserialización de objetos y matrices anidados, deberá crear una clase personalizada que se derive de la clase abstracta JsonConverter proporcionada por Json.Net.

Es en su derivado JsonConverter donde pone la implementación de cómo debe escribirse un objeto desde y hacia json.

Usted puede utilizar su costumbre JsonConverter así:

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

Aquí es una JsonConverter a medida que he utilizado con éxito en el pasado para alcanzar los mismos objetivos que usted esboza en su pregunta:

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); } 
} 
+0

Esta solución funciona genial. ¡Gracias! – smdrager

+0

[Aquí está esta solución en la otra publicación] (http://stackoverflow.com/a/38029052/1062224) –

Cuestiones relacionadas