JToken'dan var olmayabilecek değer elde edin (en iyi uygulamalar)


117

Json.NET kullanarak C # 'da bulunmayan JSON değerlerini almak için en iyi uygulama nedir ?

Şu anda, bazen belirli anahtar / değer çiftlerini içeren ve bazen içermeyen JSON döndüren bir JSON sağlayıcısıyla uğraşıyorum. Değerlerimi elde etmek için (belki de yanlış bir şekilde) bu yöntemi kullanıyorum (örneğin bir çift almak için):

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

Şimdi bu iyi çalışıyor, ancak birçoğu olduğunda hantal. Bir uzatma yöntemi yazmayı bıraktım ve ancak yazdıktan sonra aptal olup olmadığımı merak ettim ... her neyse, işte uzatma yöntemi (sadece çift ve dizge için durumları dahil ediyorum, ancak gerçekte epeyce var Daha):

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

Ve burada uzantı yönteminin kullanımına bir örnek verilmiştir:

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

BTW, Lütfen gerçekten aptalca bir sorunun ne olabileceğini affedin, çünkü bunun için yerleşik bir işlev olması gereken bir şey gibi görünüyor ... Google ve Json.NET belgelerini denedim , ancak çözüm bulmada ya beceriksizim sorum ya da belgelerde net değil.


Biraz geç olduğunu biliyorum, ancak GetValueaşağıdaki basitleştirilmiş sürümü denemek isteyebilirsiniz
LB

Yanıtlar:


210

Genel yöntemin Value()amacı budur. Null yapılabilir değer türleri ve ??operatörle birleştirirseniz tam olarak istediğiniz davranışı elde edersiniz :

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

4
Bu bir uzatma yöntemidir.
Dave Van den Eynde

2
@PaulHazen, o kadar da kötü değil ... Sadece tekerleği biraz yeniden icat ettin.
devinbost

Json'da "genişlik" yoksa ve JToken boşsa bu işe yaramaz
Deepak

2
@Deepak "Genişlik" yoksa çalışır. Tabii eğer işi değil jTokenise null, ancak bu soru sorulduğunda bu değil. Ve kolayca null koşullu operatörü kullanarak onu düzeltirim: width = jToken?.Value<double?>("width") ?? 100;.
svick

1
JToken.Value<T>JToken bir JValue ise bir istisna atar
Kyle Delaney

22

Ben yazardım GetValueaşağıda

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

Bu şekilde yalnızca temel türlerin değil, aynı zamanda karmaşık nesnelerin değerini de elde edebilirsiniz. İşte bir örnek

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

Bu oldukça havalı, ancak yalnızca basit veri türlerinin bana verdiği endişelerin ayrılmasını seviyorum. JSON ayrıştırması söz konusu olduğunda, bu ayrım kavramı biraz bulanık olsa da. Gözlemci / gözlemlenebilir bir model uyguladığım için (mvvm ile de), tüm ayrıştırmamı tek bir yerde tutma ve basit tutma eğilimindeyim (bunun bir kısmı da bana döndürülen verilerin öngörülemezliğidir).
Paul Hazen

@PaulHazen Seni anladığımı söyleyemem. Sorunuz şuydu retrieving JSON values that may not even existve tek önerdiğim GetValueyöntemi değiştirmekti . Sanırım istediğiniz gibi çalışıyor
LB

Umarım bu sefer biraz daha net olabilirim. Metodunuz harika çalışıyor ve tam olarak istediğimi başaracak. Bununla birlikte, sorumda açıklanmayan daha büyük bağlam, üzerinde çalıştığım belirli kodun yüksek oranda aktarılabilir olmasını istediğim kod olmasıdır. Yönteminizin yoluna çıktığı tartışılabilir olsa da, GetValue <T> 'den nesnelerin serisini kaldırma yeteneğini sunar; bu, kodumu daha iyi bir JSON ayrıştırıcısına sahip bir platforma taşımak uğruna kaçınmak istediğim bir modeldir. , Örneğin Win8). Yani, sorduğum şey için, evet, kodunuz mükemmel olurdu.
Paul Hazen

9

Jetonun var olup olmadığını şu şekilde kontrol edebilirsiniz:

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

"Sonuç" ta "Öğeler" olup olmadığını kontrol eder.

Bu, istisnaya neden olan çalışmayan bir örnektir:

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

3

Sadece döküm yazabilirsiniz ve sizin için dönüşümü yapacaktır, örneğin

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

nullNesnede söz konusu anahtar yoksa otomatik olarak geri dönecektir , bu nedenle test etmeye gerek yoktur.


1

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

Örneğin

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


1

Bu, boş değerleri halleder

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

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

body?.SelectToken("path-double-prop")?.ToObject<double>();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.