Obtenga valor de JToken que puede no existir (mejores prácticas)


¿Cuál es la mejor práctica para recuperar valores JSON que pueden ni siquiera existir en C# usando Json.NET ?

Ahora mismo estoy tratando con un proveedor JSON que devuelve JSON que a veces contiene ciertos pares clave/valor, y a veces no lo hace. He estado usando (quizás incorrectamente) este método para obtener mis valores (ejemplo para obtener un doble):

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

Ahora eso funciona bien, pero cuando hay muchos de ellos es engorroso. Terminé escribiendo un método de extensión, y solo después de escribirlo me pregunté si tal vez estaba siendo estúpido... de todos modos, aquí está el método de extensión (solo incluyo casos para double y string, pero en realidad tengo bastantes más):

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;
}

Y aquí hay un ejemplo del uso del método de extensión:

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

Por cierto, Por favor perdone lo que puede ser una pregunta realmente tonta, ya que parece algo para lo que debería haber una función incorporada... Probé Google, y Json.NET documentación, sin embargo yo soy inepto en encontrar la solución a mi pregunta o no está claro en la documentación.

 87
Author: svick, 2012-03-06

6 answers

Esto es más o menos lo que el método genérico Value() es para. Obtendrá exactamente el comportamiento que desea si lo combina con tipos de valores nullables y el operador ??:

width = jToken.Value<double?>("width") ?? 100;
 169
Author: svick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-06 18:15:54

Escribiría GetValue como a continuación

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;
}

De esta manera puede obtener el valor no solo de los tipos básicos, sino también de los objetos complejos. He aquí una muestra

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");
 14
Author: L.B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-06 20:47:47

Aquí es cómo puede comprobar si el token existe:

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

Comprueba si "Items" existe en "Result".

Este es un ejemplo que no funciona que causa excepción:

if (jobject["Result"]["Items"] != null) { ... }
 4
Author: Artur Alexeev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-01 18:45:25

Simplemente puede encasillar, y hará la conversión por usted, por ejemplo,

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

Devolverá automáticamente null si dicha clave no está presente en el objeto, por lo que no hay necesidad de probarlo.

 2
Author: Dave Van den Eynde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-03 06:58:32

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

Por ejemplo

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

 1
Author: Zhenyang Hua,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-30 15:50:14

Esto se encarga de nulls

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

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

body?.SelectToken("path-double-prop")?.ToObject<double>();
 0
Author: Max,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-05 04:09:08