Come deserializzare l’object che può essere un array o un dizionario con Newtonsoft?

Sto usando un’API che restituisce un object json che ho bisogno di deserializzare. Il mio problema è che uno dei membri di tali oggetti è a volte un array vuoto (“[]”) e talvolta un dizionario (“{” 1 “: {…},” 2 “: {…}}” ). Voglio deserializzare in un array o in un dizionario, dato che non mi occupo degli ID, voglio solo un elenco di tutti gli oggetti. Ecco come ho deserializzato l’object:

var response = JsonConvert.DeserializeObject(json); 

Ed ecco la definizione della class Response:

 public class Response { [JsonProperty(PropertyName = "variations")] public Dictionary Variations { get; set; } } 

Funziona bene quando Response contiene un dizionario nel suo campo delle varianti, ma fallisce quando contiene un array vuoto. Sto ricevendo un errore da Newtonsoft che dice che un array non può essere deserializzato in un dizionario. Se definisco la proprietà Variations come array, funziona con array vuoti, ma fallisce quando si tratta di un dizionario. Cosa potrei fare per deserializzare correttamente entrambi i possibili valori, o per ignorare gli array vuoti e impostare Variations su null quando si tratta di un array invece di fallire.

Grazie.

Ecco una variazione (scusa per il gioco di parole) sull’esempio di Carl. Avevo un bisogno simile, ma invece di restituire un dizionario, avevo bisogno di un array. L’API che sto usando dice che restituisce un array. Tuttavia, nel caso in cui vi sia un solo elemento nel risultato, viene invece restituito come object!

 public class VarationsContainer { [JsonIgnore] public Varation[] Varations { get { return ParseObjectToArray(VariationObject); } } [JsonProperty(PropertyName = "varations")] public object VarationsObject { get; set; } protected T[] ParseObjectToArray(object ambiguousObject) { var json = ambiguousObject.ToString(); if (String.IsNullOrWhiteSpace(json)) { return new T[0]; // Could return null here instead. } else if (json.TrimStart().StartsWith("[")) { return JsonConvert.DeserializeObject(json); } else { return new T[1] { JsonConvert.DeserializeObject(json) }; } } } 

Spero che questo sia utile per altri utenti tristi dell’API.

Ecco una soluzione alternativa che utilizza JsonConverter

 public class Response { [JsonProperty(PropertyName = "variations")] [JsonConverter(typeof(EmptyArrayOrDictionaryConverter))] public Dictionary Variations { get; set; } } public class EmptyArrayOrDictionaryConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType.IsAssignableFrom(typeof(Dictionary)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); if (token.Type == JTokenType.Object) { return token.ToObject(objectType); } else if (token.Type == JTokenType.Array) { if (!token.HasValues) { // create empty dictionary return Activator.CreateInstance(objectType); } } throw new JsonSerializationException("Object or empty array expected"); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } } 

Ecco la soluzione che ho usato:

  public Dictionary Variations { get { var json = this.VariationsJson.ToString(); if (json.RemoveWhiteSpace() == EmptyJsonArray) { return new Dictionary(); } else { return JsonConvert.DeserializeObject>(json); } } } [JsonProperty(PropertyName = "variations")] public object VariationsJson { get; set; } 

Fondamentalmente, le variazioni vengono prima deserializzate in un object di base. Quando voglio leggere il valore, controllo se l’object è un array vuoto, e in tal caso restituisco un dizionario vuoto. Se l’object è un buon dizionario, lo deserializzo e lo restituisco.