2013-05-04 11 views
7

Ho notato ci sono alcuni altri risultati su StackOverflow a questa domanda, ma non sembrano lavorare o sono vaghi. Usando il risultato più popolare, ho messo insieme questo:Come posso utilizzare JSON.NET per gestire un valore che a volte è un oggetto e talvolta una matrice dell'oggetto?

Il problema è che quando JSON ritorna e viene serializzato in uno dei miei tipi personalizzati, uno dei bit di JSON è talvolta un array, e qualche volta solo un stringa. Se il mio tipo personalizzato ha una stringa e il JSON è un array, viene visualizzato un errore. Lo stesso accade al contrario, se il JSON è un oggetto e il mio tipo personalizzato è un array. Non può semplicemente mapparlo alla proprietà.

Ho deciso di risolverlo, voglio scavalcare la deserializzazione di questa particolare proprietà, e se si tratta di un oggetto, voglio convertirlo in un array di 1 oggetto.

Nell'oggetto sto serializzazione a, ho aggiunto un JsonConverter che penso sta andando a ignorare il modo in cui è deserialised.

[JsonConverter(typeof(ArrayOrSingleObjectConverter<string>))] 
public List<string> person { get; set; } 

L'idea è che il convertitore personalizzato convertirà un singolo oggetto in un array. Quindi se il JSON è "Ciao" imposterà la persona come una lista contenente "Ciao" invece di lanciare un'eccezione che dice che non può convertire la stringa in Elenco.

Se è già una matrice, si deve solo lasciarlo solo.

Il convertitore si presenta così:

public class ArrayOrSingleObjectConverter<T> : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return true; // Not sure about this but technically it can accept an array or an object, so everything is game. 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (objectType == typeof(List<T>)) 
     { 
      return serializer.Deserialize<List<T>>(reader); 
     } 
     else 
     { 
      var singleObject = serializer.Deserialize<T>(reader); 
      var objectAsList = new List<T>(); 
      objectAsList.Add(singleObject); 
      return objectAsList; 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Non funziona. Il codice precedente lancia un'eccezione cercando di deserializzare una singola stringa dicendo che non può lanciarla in una lista all'interno dell'istruzione if (il 'objectype' è comunque una lista).

sto lottando per capire esattamente che cosa i metodi di lettura e scrittura stanno facendo. Nell'altra risposta su StackOverflow, suggerisce di lanciare un NotImplementedException nel metodo di lettura. Ma se lo faccio, viene chiamato il metodo di lettura e l'eccezione viene generata.

penso di essere sulla strada giusta, ma ho bisogno di una spintarella nella giusta direzione. Penso di essere un po 'confuso su cosa stia facendo il metodo ReadJSon e su cosa significano i suoi parametri.

Non capisco veramente da dove provenga il valore deserializzante poiché non l'ho specificato nella chiamata al metodo Deserialize.

io sono un po 'fuori dalla mia profondità su questo.

+0

non è possibile deserializzare quell'oggetto "variabile" in un oggetto 'System.Object'? Potresti quindi controllare il tipo di runtime e fare le tue cose. –

risposta

9

che dovevo fare qualcosa di simile la scorsa settimana e mi si avvicinò con la seguente, che funziona bene per una lista piuttosto che una serie

internal class GenericListCreationJsonConverter<T> : JsonConverter 
{ 

    public override bool CanConvert(Type objectType) 
    { 
     return true; 
    } 

    public override bool CanRead 
    { 
     get { return true; } 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.StartArray) 
     { 
      return serializer.Deserialize<List<T>>(reader); 
     } 
     else 
     { 
      T t = serializer.Deserialize<T>(reader); 
      return new List<T>(new[] { t }); 
     } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
+0

Eccellente grazie, ho finito per capire qualcosa di simile alla fine, ma mi piace il tuo metodo dato che ero in lotta con i generici :) – NibblyPig

1

mi piace questo metodo che rende Json.NET fare tutto il pesante sollevamento. E come risultato, supporta tutto ciò che supporta Json.NET (Lista <>, ArrayList, array fortemente tipizzati, ecc.).

public class FlexibleCollectionConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.StartArray) 
     { 
      return serializer.Deserialize(reader, objectType); 
     } 

     var array = new JArray(JToken.ReadFrom(reader)); 
     return array.ToObject(objectType); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof (IEnumerable).IsAssignableFrom(objectType); 
    } 
} 
+0

Non funziona per json array –

Problemi correlati