2012-07-19 10 views
14

Próbuję przekonwertować niektóre starsze prace, aby używać Newtonsoft JSON.NET. Domyślna obsługa za pomocą metody System.Web.Script.Serialization.JavaScriptSerializer.Deserialize (np. Jeśli nie określono typu celu) to zwrócenie obiektu Dictionary<string,object> dla obiektów wewnętrznych.Deserializuj rekursywnie JSON do IDictionary <ciąg, obiekt>

Jest to naprawdę bardzo przydatny podstawowy typ JSON, ponieważ jest on również typem bazowym używanym przez ExpandoObjects i jest najbardziej sensowną implementacją wewnętrzną dla typów dynamicznych.

Gdybym określić tego typu, np .:

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

JSON.NET będzie poprawnie deserializowania zewnętrzną strukturę obiektu, ale zwraca JObject typ dla wszelkich wewnętrznych struktur. To, czego naprawdę potrzebuję, to ta sama zewnętrzna struktura, która ma być użyta do jakichkolwiek wewnętrznych struktur typu obiektowego.

Czy istnieje sposób określenia typu, który ma być używany dla obiektów wewnętrznych, a nie tylko zwracany typ zewnętrzny?

Odpowiedz

7

Podczas odśrodkowywania złożonych obiektów przy użyciu Json, należy dodać ustawienia JsonSerializer jako parametr. Zapewni to prawidłowe deserializacje wszystkich typów wewnętrznych.

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

Kiedy Szeregowania swój cel, można użyć SerializerSettings:

string json= JsonConvert.SerializeObject(myObject, _jsonSettings) 

następnie po deserializacji, przeznaczenie:

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

Również podczas serializacji, dodać JsonSerializerSettings do twój SerializeObject (obiekt, ustawienia)

Edytuj: Możesz również zmienić t on TypeNameHandling i TypeNameAssemblyFormat, jeśli potrzebujesz. Mam je ustawione odpowiednio na "Wszystkie" i "Pełne", aby upewnić się, że moje złożone obiekty są serializowane i deserializowane poprawnie bez wątpienia, ale firma intellisense udostępnia inne możliwości:

+0

Czy to jest poprawna odpowiedź? –

+1

@LukePuplett Nie sądzę, że jest to poprawne, w oparciu o zadane pytanie. –

+0

Na podstawie pytania nie jest to poprawna odpowiedź w ogóle. –

15

Aby uzyskać Json.Net w celu deserializacji łańcucha JSON do IDictionary<string, object> włącznie z deserializacją zagnieżdżonych obiektów i tablic, musisz utworzyć klasę niestandardową, która pochodzi z klasy abstrakcyjnej JsonConverter dostarczonej przez Json.Net.

To jest w twojej wyprowadzonej JsonConverter, gdzie umieszczasz implementację sposobu, w jaki obiekt powinien być zapisywany do iz json.

można używać niestandardowych JsonConverter tak:

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

Oto zwyczaj JsonConverter Użyłem z powodzeniem w przeszłości, aby osiągnąć te same cele, jak przedstawić w swoim pytaniu:

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

To rozwiązanie działa świetnie. Dzięki! – smdrager

+0

[Tutaj jest to rozwiązanie w drugim poście] (http://stackoverflow.com/a/38029052/1062224) –

Powiązane problemy