Ottieni valore da JToken che potrebbe non esistere (best practice)


117

Qual è la procedura migliore per il recupero dei valori JSON che potrebbero non esistere nemmeno in C # utilizzando Json.NET ?

In questo momento ho a che fare con un provider JSON che restituisce JSON che a volte contiene determinate coppie chiave / valore e talvolta no. Ho usato (forse in modo errato) questo metodo per ottenere i miei valori (esempio per ottenere un doppio):

if(null != jToken["width"])
    width = double.Parse(jToken["width"].ToString());
else
    width = 100;

Ora funziona bene, ma quando ce ne sono molti è ingombrante. Ho finito per scrivere un metodo di estensione, e solo dopo averlo scritto mi sono chiesto se forse stavo facendo lo stupido ... comunque, ecco il metodo di estensione (includo solo casi per double e string, ma in realtà ne ho parecchi Di Più):

public static T GetValue<T>(this JToken jToken, string key,
                            T defaultValue = default(T))
{
    T returnValue = defaultValue;

    if (jToken[key] != null)
    {
        object data = null;
        string sData = jToken[key].ToString();

        Type type = typeof(T);

        if (type is double)
            data = double.Parse(sData);
        else if (type is string)
            data = sData;

        if (null == data && type.IsValueType)
            throw new ArgumentException("Cannot parse type \"" + 
                type.FullName + "\" from value \"" + sData + "\"");

        returnValue = (T)Convert.ChangeType(data, 
            type, CultureInfo.InvariantCulture);
    }

    return returnValue;
}

Ed ecco un esempio di utilizzo del metodo di estensione:

width = jToken.GetValue<double>("width", 100);

A proposito, per favore perdona quella che potrebbe essere una domanda davvero stupida, dal momento che sembra che dovrebbe esserci una funzione incorporata per ... Ho provato Google e la documentazione di Json.NET , tuttavia non sono in grado di trovare la soluzione per la mia domanda o non è chiara nella documentazione.


So che è un po 'tardi, ma potresti provare questa versione semplificata di GetValueseguito
LB

Risposte:


210

Questo è più o meno lo scopo del metodo generico Value(). Ottieni esattamente il comportamento che desideri se lo combini con tipi di valore nullable e l' ??operatore:

width = jToken.Value<double?>("width") ?? 100;

4
È un metodo di estensione.
Dave Van den Eynde

2
@PaulHazen, non è così male ... Hai appena reinventato un po 'la ruota, tutto qui.
devinbost

Questo non funziona se "larghezza" non esiste nel json e JToken è nullo
Deepak

2
@ Deepak Funziona se "width" non esiste. Ovviamente non funziona se lo jTokenè null, ma non è quello che la domanda ha posto. E si può facilmente risolvere che utilizzando il nulla operatore condizionale: width = jToken?.Value<double?>("width") ?? 100;.
svick

1
JToken.Value<T>genera un'eccezione se il JToken è un JValue
Kyle Delaney

22

Vorrei scrivere GetValuecome sotto

public static T GetValue<T>(this JToken jToken, string key, T defaultValue = default(T))
{
    dynamic ret = jToken[key];
    if (ret == null) return defaultValue;
    if (ret is JObject) return JsonConvert.DeserializeObject<T>(ret.ToString());
    return (T)ret;
}

In questo modo puoi ottenere il valore non solo dei tipi di base ma anche degli oggetti complessi. Ecco un esempio

public class ClassA
{
    public int I;
    public double D;
    public ClassB ClassB;
}
public class ClassB
{
    public int I;
    public string S;
}

var jt = JToken.Parse("{ I:1, D:3.5, ClassB:{I:2, S:'test'} }");

int i1 = jt.GetValue<int>("I");
double d1 = jt.GetValue<double>("D");
ClassB b = jt.GetValue<ClassB>("ClassB");

È abbastanza interessante, ma mi piace la separazione delle preoccupazioni che mi dà solo ottenere semplici tipi di dati. Sebbene l'idea di tale separazione sia un po 'confusa quando si tratta di analisi JSON. Dal momento che implemento un modello osservatore / osservabile (anche con mvvm), tendo a mantenere tutta la mia analisi in un unico posto e mantenerla semplice (parte di ciò è anche l'imprevedibilità dei dati restituiti).
Paul Hazen

@PaulHazen Non posso dire di capirti. La tua domanda era retrieving JSON values that may not even existe tutto quello che ho proposto è stato di cambiare il tuo GetValuemetodo. Penso che funzioni come vuoi
LB

Spero di poter essere un po 'più chiaro questa volta. Il tuo metodo funziona alla grande e realizzerebbe esattamente quello che voglio. Tuttavia, il contesto più ampio non spiegato nella mia domanda è che il codice particolare su cui sto lavorando è codice che voglio sia altamente trasferibile. Sebbene sia discutibile che il tuo metodo si intrometta, introduce la possibilità di deserializzare oggetti da GetValue <T>, che è un modello che voglio evitare per il gusto di spostare il mio codice su una piattaforma che ha un parser JSON migliore (ad esempio , Win8 per esempio). Quindi, per quello che ho chiesto, sì, il tuo codice sarebbe perfetto.
Paul Hazen

9

Ecco come puoi verificare se il token esiste:

if (jobject["Result"].SelectToken("Items") != null) { ... }

Controlla se "Articoli" esiste in "Risultato".

Questo è un esempio NON funzionante che causa un'eccezione:

if (jobject["Result"]["Items"] != null) { ... }

3

Puoi semplicemente typecast, e farà la conversione per te, ad es

var with = (double?) jToken[key] ?? 100;

Tornerà automaticamente nullse detta chiave non è presente nell'oggetto, quindi non è necessario testarla.


1

TYPE variable = jsonbody["key"]?.Value<TYPE>() ?? DEFAULT_VALUE;

per esempio

bool attachMap = jsonbody["map"]?.Value<bool>() ?? false;


1

Questo si prende cura dei null

var body = JObject.Parse("anyjsonString");

body?.SelectToken("path-string-prop")?.ToString();

body?.SelectToken("path-double-prop")?.ToObject<double>();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.