c# - JContainer, JObject, JToken y Linq confusión
json json.net (2)
Realmente no necesita preocuparse por JContainer
en la mayoría de los casos. Está allí para ayudar a organizar y estructurar LINQ-to-JSON en código bien factorizado.
La jerarquía de JToken
ve así:
JToken - abstract base class
JContainer - abstract base class of JTokens that can contain other JTokens
JArray - represents a JSON array (contains an ordered list of JTokens)
JObject - represents a JSON object (contains a collection of JProperties)
JProperty - represents a JSON property (a name/JToken pair inside a JObject)
JValue - represents a primitive JSON value (string, number, boolean, null)
Así que ya ves, un objeto JObject
es un JContainer
, que es un JToken
.
Aquí está la regla básica de oro:
- Si sabe que tiene un objeto (denotado por llaves
{
y}
en JSON), useJObject
- Si sabe que tiene una matriz o lista (denotada entre corchetes
[
y]
), useJArray
- Si sabes que tienes un valor primitivo, usa
JValue
- Si no sabe qué tipo de token tiene, o quiere poder manejar cualquiera de los anteriores de una manera general, use
JToken
. Luego, puede verificar su propiedadType
para determinar qué tipo de token es y emitirlo de manera apropiada.
Tengo problemas para entender cuándo usar JContainer
, JObject
y JToken
. Entiendo por los "estándares" que JObject
está compuesto por JProperties
y que JToken
es la clase abstracta básica para todos los tipos de JToken
, pero no entiendo JContainer
.
Estoy usando C # y acabo de comprar LinqPad Pro 5.
Tengo un origen de datos JSON en un archivo, así que estoy deserializando el contenido de ese archivo con éxito usando esta declaración:
string json;
using (StreamReader reader = new StreamReader(@"myjsonfile.json"))
{
json = reader.ReadToEnd();
}
En ese momento, tomo el objeto de cadena JSON y lo deserializo a un objeto JObject
(y este podría ser mi error. ¿Quizás necesito hacer que jsonWork
un JToken
o JContainer
?):
JObject jsonWork = (JObject)JsonConvert.DeserializeObject(json);
En mis datos JSON (la cadena representada por JSON), tengo tres objetos: el objeto de nivel superior es similar a este:
{
"Object1" : { ... },
"Object2" : { ... },
"Object3" : { ... }
}
Cada objeto está compuesto de todo tipo de tokens (matrices, cadenas, otros objetos, etc.), por lo que es JSON dinámico. (Utilicé puntos suspensivos como marcadores de posición en lugar de enturbiar esta pregunta con gran cantidad de datos JSON).
Sin embargo, quiero procesar "Object1"
, "Object2"
y "Object3"
separado utilizando LINQ. Entonces, idealmente, me gustaría algo como esto:
// these lines DO NOT work
var jsonObject1 = jsonWork.Children()["Object1"]
var jsonObject2 = jsonWork.Children()["Object2"]
var jsonObject3 = jsonWork.Children()["Object3"]
Pero las líneas anteriores fallan.
Utilicé var
arriba porque no tengo idea de qué tipo de objeto debería usar: JContainer
, JObject
o JToken
! Solo para que sepa lo que quiero hacer, una vez que las variables jsonObject#
anteriores estén asignadas correctamente, me gustaría usar LINQ para consultar el JSON que contienen. Aquí hay un ejemplo muy simple:
var query = from p in jsonObject1
where p.Name == "Name1"
select p
Por supuesto, mi LINQ finalmente filtrará las matrices JSON, objetos, cadenas, etc., en la variable jsonObject
. Creo que una vez que me ponga en marcha, puedo usar LinqPad para ayudarme a filtrar el JSON utilizando LINQ.
Descubrí que si uso:
// this line WORKS
var jsonObject1 = ((JObject)jsonWork).["Object1"];
Entonces obtengo un tipo de jsonObject1
en jsonObject1
. ¿Es este el enfoque correcto?
No tengo claro cuándo / por qué se usaría JContainer
cuando parece que los objetos JToken
y JObject
funcionan bastante bien con LINQ. ¿Cuál es el propósito de JContainer
?
JContainer
es una clase base para elementos JSON que tienen elementos secundarios. JObject
, JArray
, JProperty
y JConstructor
heredan de él.
Por ejemplo, el siguiente código:
(JObject)JsonConvert.DeserializeObject("[1, 2, 3]")
JContainer
una JContainer
InvalidCastException
, pero si la JContainer
a un JContainer
, estaría bien.
Con respecto a su pregunta original, si sabe que tiene un objeto JSON en el nivel superior, puede usar:
var jsonWork = JObject.Parse(json);
var jsonObject1 = o["Object1"];