2012-03-06 7 views
79

¿Cuál es la mejor práctica para recuperar valores JSON que ni siquiera existen en C# utilizando Json.NET?Obtiene el valor de JToken que puede no existir (mejores prácticas)

En este momento estoy tratando con un proveedor JSON que devuelve JSON que algunas veces contiene ciertos pares clave/valor, y otras veces no. He estado usando (quizás incorrectamente) este método para obtener mis valores (ejemplo para conseguir un doble):

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

Ahora que funciona bien, pero cuando hay una gran cantidad de ellos es engorroso. Terminé escribiendo un método de extensión, y solo después de escribiendo me pregunté si tal vez estaba siendo estúpido ... de todos modos, aquí está el método de extensión (solo incluyo casos para doble y cadena, pero en realidad tengo bastante unos cuantos 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í está un ejemplo del uso del método de extensión:

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

Por cierto, por favor perdona lo que puede ser una pregunta muy tonta, ya que parece que algo debe haber una función incorporada para ... Intenté Google, y Json.NET documentación, sin embargo, o soy inepto t encontrar la solución a mi pregunta o no está claro en la documentación.

+0

Sé que es un poco tarde, pero es posible que desee probar esta versión simplificada del 'GetValue' continuación –

Respuesta

150

Esto es más o menos lo que el método genérico Value() es para. Se obtiene exactamente el comportamiento que desea si se combina con los tipos de valor anulables y la ?? operador:

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

Gracias @svick! Eso es exactamente lo que estaba buscando. Como sospechaba, es algo simple, similar y ya está en su lugar.* palma de la cara * –

+3

Es un método de extensión. –

+1

@PaulHazen, no es tan malo ... Acabas de reinventar la rueda un poco. – devinbost

12

me gustaría escribir 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 se puede obtener el valor de no sólo los tipos básicos pero también los objetos complejos. Este es un ejemplo

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"); 
+0

Eso es genial, pero me gusta la separación de las preocupaciones que solo me da obtener tipos de datos simples. Aunque la noción de esa separación es un poco borrosa cuando se trata de análisis JSON. Dado que implemento un modelo observable/observable (con mvvm también), tiendo a mantener todo mi análisis sintáctico en un solo lugar y mantenerlo simple (parte de eso también es la imprevisibilidad de los datos que me son devueltos). –

+0

@PaulHazen No puedo decir que te entiendo. Tu pregunta era 'recuperar valores JSON que ni siquiera pueden existir' y todo lo que propuse fue cambiar tu método' GetValue'. Creo que funciona como quieras –

+0

Espero que pueda ser un poco más claro esta vez. Su método funciona muy bien y lograría exactamente lo que quiero. Sin embargo, el contexto más amplio que no se explica en mi pregunta es que el código particular en el que estoy trabajando es un código que quiero que sea altamente transferible. Si bien es discutible que su método se interponga, introduce la capacidad de deserializar objetos de GetValue , que es un patrón que quiero evitar para mover mi código a una plataforma que tenga un mejor analizador JSON (por ejemplo, Win8). por ejemplo). Entonces, por lo que pregunté, sí, su código sería perfecto. –

2

Simplemente puede encasillarse, y lo hará la conversión para usted, por ejemplo,

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

Se volverá automáticamente null si dicha clave no está presente en el objeto, así que no hay necesidad de probar para ello.

3

Así es como se puede comprobar si existe el token:

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

Comprueba si existe "Artículos" en "Resultado".

Este es un ejemplo que no de trabajo que provoca excepción:

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

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

por ejemplo

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