存在しない可能性があるJTokenから値を取得します(ベストプラクティス)


117

Json.NETを使用してC#にも存在しない可能性があるJSON値を取得するためのベストプラクティスは何ですか?

現在、私はJSONプロバイダーを扱っています。JSONプロバイダーは、特定のキーと値のペアを含む場合と含まない場合があるJSONを返します。私は(おそらく間違って)このメソッドを使用して値を取得しています(doubleを取得する例):

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

今では問題なく動作しますが、それらがたくさんあると面倒です。結局、拡張メソッドを書いてしまいましたが、それ書いて初めて私が愚かだったのではないかと思いました...とにかく、ここに拡張メソッドがあります(doubleとstringの場合のみを含めますが、実際にはかなり多くのもっと):

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

そして、これは拡張メソッドの使用例です:

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

ところで、組み込みの関数があるはずのように思えるので、本当に馬鹿げた質問になるかもしれないことを許してください...私はGoogleとJson.NETを試しましたドキュメントを解決策を見つけることにません私の質問またはそれはドキュメントでは明確ではありません。


私はそれが少し遅れていることを知っていますが、GetValue以下のこの簡略化されたバージョンを試すことをお勧めします
LB

回答:


210

これが汎用メソッドのValue()目的です。null許容値型および??演算子と組み合わせると、希望どおりの動作が得られます。

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

4
これは拡張メソッドです。
Dave Van den Eynde 2013年

2
@PaulHazen、それはそれほど悪くはない...あなたは少しだけホイールを再発明した。
devinbost 16

「幅」がjsonに存在せず、JTokenがnullの場合、これは機能しません
Deepak

2
@Deepak「幅」が存在しない場合は機能します。もちろん、の場合jTokenは機能しませんがnull、それは質問の答えではありません。また、null条件演算子を使用することで簡単に修正できますwidth = jToken?.Value<double?>("width") ?? 100;
2018年

1
JToken.Value<T>JTokenがJValueである場合、例外をスローします
カイルデラニー

22

GetValue以下のように書きます

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

このようにして、基本型だけでなく複雑なオブジェクトの値も取得できます。こちらがサンプルです

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

それはかなりクールですが、単純なデータ型を取得することのみが私に与える懸念の分離が好きです。JSON解析に関しては、その分離の概念は少しあいまいですが。私はオブザーバー/オブザーバブルモデル(mvvmも使用)を実装しているため、すべての解析を1か所にまとめ、シンプルに保つ傾向があります(その一部は、返されるデータの予測不可能性でもあります)。
Paul Hazen、2012年

@PaulHazen私はあなたを理解しているとは言えません。あなたの質問はretrieving JSON values that may not even exist、そして私が提案したすべてはあなたのGetValue方法を変えることでした。私はそれがあなたが望むように機能すると思います
LB

今回はもう少しはっきりさせていただければ幸いです。あなたの方法はうまく機能し、私が望むものを正確に達成します。しかし、私の質問で説明されていないより大きなコンテキストは、私が取り組んでいる特定のコードが、高度に転送可能にしたいコードであることです。メソッドが邪魔になることは間違いありませんが、GetValue <T>からオブジェクトをデシリアライズする機能が導入されています。これは、より良いJSONパーサーを持つプラットフォームにコードを移動するために避けたいパターンです(たとえば、 、Win8など)。だから、私が尋ねたことについては、はい、あなたのコードは完璧です。
Paul Hazen

9

トークンが存在するかどうかを確認する方法は次のとおりです。

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

「結果」に「アイテム」が存在するか確認します。

これは、例外の原因となる機能しない例です。

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

3

あなたは単にタイプキャストすることができ、それはあなたのために変換を行います、例えば

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

null上記のキーがオブジェクトに存在しない場合は自動的に返されるため、テストする必要はありません。


1

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

例えば

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


1

これはnullを処理します

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

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

body?.SelectToken("path-double-prop")?.ToObject<double>();
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.