131 votes

Tirer de la valeur de JToken qui n'existe peut-être pas (meilleures pratiques)

Quelle est la meilleure pratique pour récupérer des valeurs JSON qui n'existent peut-être même pas en C# à l'aide de Json.NET ?

Pour l'instant, j'ai affaire à un fournisseur JSON qui renvoie un JSON contenant parfois certaines paires clé/valeur, et parfois non. J'ai utilisé (peut-être incorrectement) cette méthode pour obtenir mes valeurs (exemple pour obtenir un double) :

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

Maintenant, cela fonctionne bien, mais quand il y en a beaucoup, c'est encombrant. J'ai fini par écrire une méthode d'extension, et seulement après En écrivant cela, je me suis demandé si je n'étais pas en train d'être stupide... Quoi qu'il en soit, voici la méthode d'extension (je n'inclus que les cas pour le double et la chaîne, mais en réalité j'en ai beaucoup plus) :

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

Et voici un exemple d'utilisation de la méthode d'extension :

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

Pardonnez cette question qui pourrait être stupide, car il semble qu'il devrait y avoir une fonction intégrée pour cela... J'ai essayé Google, et Json.NET Cependant, soit je ne parviens pas à trouver la solution à ma question, soit elle n'est pas claire dans la documentation.

0 votes

Je sais que c'est un peu tard, mais vous pouvez essayer cette version simplifiée de GetValue en dessous de

0 votes

string rootValue = jToken.Value<string>()

230voto

svick Points 81772

C'est à peu près ce que la méthode générique Value() est pour. Vous obtenez exactement le comportement que vous souhaitez si vous le combinez avec des types de valeurs invalides et la fonction ?? opérateur :

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

3 votes

@PaulHazen, ce n'est pas si mal... Vous avez juste réinventé un peu la roue, c'est tout.

0 votes

Cela ne fonctionne pas si "width" n'existe pas dans le json et si JToken est nul.

5 votes

@Deepak Cela fonctionne si "width" n'existe pas. Bien sûr, cela ne fonctionne pas si jToken es null mais ce n'est pas ce que la question demandait. Et vous pouvez facilement résoudre ce problème en utilisant l'opérateur conditionnel nul : width = jToken?.Value<double?>("width") ?? 100; .

25voto

L.B Points 54001

J'écrirais GetValue comme suit

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 cette façon, vous pouvez obtenir la valeur non seulement des types de base mais aussi des objets complexes. Voici un exemple

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 votes

C'est plutôt cool, mais j'aime la séparation des préoccupations que seuls les types de données simples me procurent. Bien que la notion de cette séparation soit un peu floue lorsqu'il s'agit de l'analyse de JSON. Puisque j'implémente un modèle observateur/observable (avec mvvm également), j'ai tendance à garder tout mon parsing en un seul endroit, et à le garder simple (une partie de cela est aussi l'imprévisibilité des données qui me sont retournées).

0 votes

@PaulHazen Je ne peux pas dire que je vous comprends. Votre question était retrieving JSON values that may not even exist et tout ce que j'ai proposé, c'est de changer votre GetValue méthode. Je pense que cela fonctionne comme vous le voulez

0 votes

J'espère que je serai un peu plus clair cette fois-ci. Votre méthode fonctionne très bien, et accomplirait exactement ce que je veux. Cependant, le contexte plus large non expliqué dans ma question est que le code particulier sur lequel je travaille est un code que je veux être hautement transférable. Bien qu'il soit possible d'argumenter que votre méthode soit un obstacle, elle introduit la possibilité de désérialiser des objets à partir de GetValue<T>, ce qui est un modèle que je veux éviter pour pouvoir déplacer mon code vers une plateforme qui a un meilleur parseur JSON (disons, Win8 par exemple). Donc, pour ce que j'ai demandé, oui, votre code serait parfait.

9voto

Artur Alexeev Points 308

Voici comment vous pouvez vérifier si le jeton existe :

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

Il vérifie si "Items" existe dans "Resultat".

Il s'agit d'un exemple qui ne fonctionne PAS et qui provoque une exception :

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

3voto

Max Points 399

Cela prend soin des nuls

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

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

body?.SelectToken("path-double-prop")?.ToObject<double>();

3voto

Dave Van den Eynde Points 8199

Vous pouvez simplement faire un tapuscrit, et il fera la conversion pour vous, par ex.

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

Il retournera automatiquement null si ladite clé n'est pas présente dans l'objet, il n'y a donc pas besoin de la tester.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X