Jak wyliczać za pomocą JObject?

111

Próbuję ustalić, jak uzyskać dostęp do danych znajdujących się w moim JObject i do końca życia nie mogę określić, jak z nich korzystać.

JObject Object = (JObject)Response.Data["my_key"];

Mogę go wydrukować na konsoli robiąc Console.WriteLine (Object) i widzę dane, wygląda to tak:

{
 "my_data" : "more of my string data"
...
}

Ale nie mam pojęcia, jak po prostu iterować / wyliczać przez to, ktoś ma jakieś pomysły? Jestem teraz bardzo zagubiony.

Geesu
źródło

Odpowiedzi:

167

Jeśli spojrzysz na dokumentację programuJObject , zobaczysz, że implementuje IEnumerable<KeyValuePair<string, JToken>>. Możesz więc iterować po prostu używając foreach:

foreach (var x in obj)
{
    string name = x.Key;
    JToken value = x.Value;
    
}
svick
źródło
3
To jest poprawne, ale z powodów, których nie rozumiem, nie możesz go używać z Linq, chyba że jawnie rzutujesz na wyliczalny typ. To znaczy ty ((IEnumerable<KeyValuePair<string, JToken>>)obj).Select(...)zamiast zwykłego starego obj.Select(...); a przynajmniej to właśnie znalazłem jako część mojego kodu.
Adrian Ratnapala
2
@AdrianRatnapala Czy twój obiekt jest zadeklarowany jako dynamiczny? Metody rozszerzające (takie jak Enumerable.Select) nie działają z tym.
svick
1
Nie, w moim przypadku objmiał typ JObject; ale JObjectwydaje się mieć podobne problemy do dynamic. Kompilator nie może wywnioskować argumentów typu .Select. Mogę je podać wprost, obj.Select<KeyValuePair<string, JToken>, (result type)>(...)działa też dla mnie
Adrian Ratnapala
3
@AdrianRatnapala Hmm, masz rację. Dzieje się tak, ponieważ JObjectwdraża oba IEnumerable<KeyValuePair<string, JToken>>i IEnumerable<JToken>(pośrednio przez JContainer).
svick
3
Jak mam go teraz używać do zagnieżdżonych JSON? Na przykład, jeśli „wartość” zawiera inny zestaw par klucz: wartość, w jaki sposób mogę użyć JToken valuedo iteracji w kolejnym zestawie par?
AlbatrossCafe
53

JObjects można wyliczyć za pomocą obiektów JProperty , rzutując je na JToken :

foreach (JProperty x in (JToken)obj) { // if 'obj' is a JObject
    string name = x.Name;
    JToken value = x.Value;
}

Jeśli masz zagnieżdżony JObject w innym JObject, nie musisz rzutować, ponieważ akcesor zwróci JToken:

foreach (JProperty x in obj["otherObject"]) { // Where 'obj' and 'obj["otherObject"]' are both JObjects
    string name = x.Name;
    JToken value = x.Value;
}
Daniel
źródło
3
Można również wygodnie używać LINQ tak: obj.Properties().Select(p => p.Name + ": " + p.Value).
itslittlejohn
To była dokładnie ta informacja, której szukałem. Dziękuję bardzo!
jhoepken
15

Odpowiedź nie zadziałała dla mnie. Nie wiem, skąd wzięło się tyle głosów. Chociaż pomogło mi to wskazać kierunek.

Oto odpowiedź, która zadziałała dla mnie:

foreach (var x in jobj)
{
    var key = ((JProperty) (x)).Name;
    var jvalue = ((JProperty)(x)).Value ;
}
jaxxbo
źródło
1
Z tym (po tym wierszu: JObject priceComplianceJson = JObject.Parse (File.ReadAllText (fullPath));) otrzymuję komunikat „Nie można przekonwertować typu„ System.Collections.Generic.KeyValuePair <string, Newtonsoft.Json.Linq.JToken> ” to 'Newtonsoft.Json.Linq.JProperty' "Usunięcie rzutowania działa jednak: var key = x.Key; var jvalue = x.Value; - przynajmniej się kompiluje ... Jutro poprawię funkcjonalność.
B. Clay Shannon
3

Dla ludzi takich jak ja, uzależnionych od linq i w oparciu o odpowiedź Svicka , tutaj podejście linq:

using System.Linq;
//...
//make it linq iterable. 
var obj_linq = Response.Cast<KeyValuePair<string, JToken>>();

Teraz możesz tworzyć wyrażenia linq takie jak:

JToken x = obj_linq
          .Where( d => d.Key == "my_key")
          .Select(v => v)
          .FirstOrDefault()
          .Value;
string y = ((JValue)x).Value;

Lub tylko:

var y = obj_linq
       .Where(d => d.Key == "my_key")
       .Select(v => ((JValue)v.Value).Value)
       .FirstOrDefault();

Lub ten do iteracji po wszystkich danych:

obj_linq.ToList().ForEach( x => { do stuff } ); 
dani herrera
źródło