web-dev-qa-db-fra.com

Confusion JContainer, JObject, JToken et Linq

J'ai du mal à comprendre quand utiliser JContainer, JObject et JToken. D'après les "normes", je comprends que JObject est composé de JProperties et que JToken est la classe abstraite de base pour tous les types JToken, mais je ne comprends pas JContainer.

J'utilise C # et je viens d'acheter LinqPad Pro 5.

J'ai une source de données JSON dans un fichier, je vais donc désérialiser le contenu de ce fichier avec succès en utilisant cette déclaration:

string json;
using (StreamReader reader = new StreamReader(@"myjsonfile.json"))
{
    json = reader.ReadToEnd();
}

À ce stade, je prends l’objet chaîne JSON et le désérialise en JObject (et c’est peut-être mon erreur. Peut-être dois-je créer jsonWork un JToken ou JContainer?):

JObject jsonWork = (JObject)JsonConvert.DeserializeObject(json);

Dans mes données JSON (la chaîne représentée par JSON), j'ai trois objets - l'objet de niveau supérieur ressemble à ceci:

{
  "Object1" : { ... },
  "Object2" : { ... },
  "Object3" : { ... }
}

Chaque objet est composé de toutes sortes de jetons (tableaux, chaînes, autres objets, etc.), il s'agit donc de JSON dynamique. (J'ai utilisé des ellipses comme espaces réservés plutôt que de compliquer la question avec beaucoup de données JSON.)

Je veux traiter "Object1", "Object2", et "Object3" séparément à l'aide de LINQ, cependant. Donc, idéalement, j'aimerais quelque chose comme ceci:

// these lines DO NOT work    
var jsonObject1 = jsonWork.Children()["Object1"]
var jsonObject2 = jsonWork.Children()["Object2"]
var jsonObject3 = jsonWork.Children()["Object3"]

Mais les lignes ci-dessus échouent.

J'ai utilisé var ci-dessus parce que je n'ai aucune idée du type d'objet que je devrais utiliser: JContainer, JObject ou JToken! Juste pour que vous sachiez ce que je veux faire, une fois ce qui précède jsonObject# les variables sont correctement affectées, je voudrais utiliser LINQ pour interroger le JSON qu'elles contiennent. Voici un exemple très simple:

var query = from p in jsonObject1
   where p.Name == "Name1"
   select p

Bien entendu, mon LINQ finira par filtrer les tableaux, objets, chaînes, etc. JSON, dans la variable jsonObject. Je pense qu'une fois que j'y vais, je peux utiliser LinqPad pour m'aider à filtrer le JSON à l'aide de LINQ.

J'ai découvert que si j'utilise:

// this line WORKS 
var jsonObject1 = ((JObject)jsonWork).["Object1"];

Ensuite, je reçois un JObject de type jsonObject1. Est-ce la bonne approche?

Je ne sais pas quand/pourquoi on utiliserait JContainer alors qu'il semble que les objets JToken et JObject fonctionnent assez bien avec LINQ. Quel est le but de JContainer?

42
Jazimov

JContainer est une classe de base pour les éléments JSON ayant des éléments enfants. JObject, JArray, JProperty et JConstructor en héritent tous.

Par exemple, le code suivant:

(JObject)JsonConvert.DeserializeObject("[1, 2, 3]")

Lancerait un InvalidCastException, mais si vous le convertissez en un JContainer, tout irait bien.

En ce qui concerne votre question initiale, si vous savez que vous avez un objet JSON au plus haut niveau, vous pouvez simplement utiliser:

var jsonWork = JObject.Parse(json);
var jsonObject1 = o["Object1"];
18
Eli Arbel

Vous n'avez pas vraiment besoin de vous soucier de JContainer dans la plupart des cas. Il est là pour vous aider à organiser et à structurer LINQ-to-JSON en code bien factorisé.

La hiérarchie JToken ressemble à ceci:

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)

Donc, vous voyez, un JObject est a JContainer =, qui est a JToken .

Voici la règle de base:

  • Si vous savez que vous avez un objet (désigné par des accolades { et } en JSON), utilisez JObject
  • Si vous savez que vous avez un tableau ou une liste (indiquée par des crochets [ et ]), utilisez JArray
  • Si vous savez que vous avez une valeur primitive, utilisez JValue
  • Si vous ne savez pas quel type de jeton vous avez ou voulez être capable de gérer l'un des éléments ci-dessus de manière générale, utilisez JToken . Vous pouvez ensuite vérifier sa propriété Type pour déterminer le type de jeton et le lancer de manière appropriée.
206
Brian Rogers