Nhận giá trị từ JToken có thể không tồn tại (thực tiễn tốt nhất)


117

Cách thực hành tốt nhất để truy xuất các giá trị JSON thậm chí không tồn tại trong C # bằng Json.NET là gì?

Ngay bây giờ tôi đang làm việc với một nhà cung cấp JSON trả về JSON đôi khi có chứa các cặp khóa / giá trị nhất định và đôi khi không. Tôi đã sử dụng (có lẽ không chính xác) phương pháp này để nhận các giá trị của tôi (ví dụ để nhận được gấp đôi):

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

Bây giờ nó hoạt động tốt, nhưng khi có rất nhiều trong số đó thì nó cồng kềnh. Cuối cùng tôi đã viết một phương thức mở rộng và chỉ sau khi viết nó, tôi mới tự hỏi liệu có thể mình ngu ngốc không ... dù sao, đây là phương thức mở rộng (tôi chỉ bao gồm các trường hợp cho chuỗi kép và chuỗi, nhưng thực tế tôi có khá nhiều hơn):

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

Và đây là một ví dụ về việc sử dụng phương thức mở rộng:

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

BTW, xin vui lòng tha thứ cho những gì có thể là một câu hỏi thực sự ngớ ngẩn, vì có vẻ như có thứ gì đó nên có chức năng tích hợp cho ... Tôi đã thử tài liệu của Google và Json.NET , tuy nhiên tôi không tìm được giải pháp cho câu hỏi của tôi hoặc nó không rõ ràng trong tài liệu.


Tôi biết là hơi muộn, nhưng bạn có thể muốn thử phiên bản đơn giản hóa GetValuedưới đây
LB

Câu trả lời:


210

Đây là khá nhiều những gì phương pháp chung Value()là cho. Bạn nhận được chính xác hành vi bạn muốn nếu bạn kết hợp nó với các loại giá trị null và ??toán tử:

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

4
Đó là một phương pháp mở rộng.
Dave Van den Eynde

2
@PaulHazen, nó không tệ ... Bạn chỉ cần phát minh lại bánh xe một chút là được.
devinbost

Điều này không hoạt động nếu "chiều rộng" không tồn tại trong json và JToken là null
Deepak

2
@Deepak Nó hoạt động nếu "chiều rộng" không tồn tại. Tất nhiên nó không hoạt động nếu jTokennull, nhưng đó không phải là những gì câu hỏi. Và bạn có thể dễ dàng khắc phục điều đó bằng cách sử dụng toán tử điều kiện null : width = jToken?.Value<double?>("width") ?? 100;.
Svick

1
JToken.Value<T>ném một ngoại lệ nếu JToken là một JValue
Kyle Delaney

22

Tôi sẽ viết GetValuenhư dưới đây

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

Bằng cách này, bạn có thể nhận được giá trị của không chỉ các loại cơ bản mà cả các đối tượng phức tạp. Đây là một mẫu

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

Điều đó khá tuyệt, nhưng tôi thích sự tách biệt các mối quan tâm mà chỉ nhận các loại dữ liệu đơn giản mang lại cho tôi. Mặc dù khái niệm về sự tách biệt đó có một chút mờ nhạt khi nói về phân tích cú pháp JSON. Vì tôi triển khai một mô hình quan sát / có thể quan sát được (với mvvm), tôi có xu hướng giữ tất cả các phân tích cú pháp của mình ở một nơi và giữ cho nó đơn giản (một phần cũng không thể đoán trước được của dữ liệu trả về cho tôi).
Paul Hazen

@PaulHazen Tôi không thể nói rằng tôi hiểu bạn. Câu hỏi của bạn là retrieving JSON values that may not even existvà tất cả những gì tôi đề xuất là thay đổi GetValuephương pháp của bạn . Tôi nghĩ rằng nó hoạt động như bạn muốn
LB

Hy vọng lần này tôi có thể rõ ràng hơn một chút. Phương pháp của bạn hoạt động rất tốt, và sẽ thực hiện chính xác những gì tôi muốn. Tuy nhiên, bối cảnh lớn hơn không được giải thích trong câu hỏi của tôi là mã cụ thể mà tôi đang làm việc là mã mà tôi muốn có khả năng chuyển nhượng cao. Mặc dù có thể cho rằng phương thức của bạn cản trở, nhưng nó giới thiệu khả năng khử lưu lượng đối tượng từ GetValue <T>, đây là mô hình mà tôi muốn tránh để chuyển mã của mình sang nền tảng có trình phân tích cú pháp JSON tốt hơn (nói , Win8 chẳng hạn). Vì vậy, đối với những gì tôi yêu cầu, vâng, mã của bạn sẽ hoàn hảo.
Paul Hazen

9

Đây là cách bạn có thể kiểm tra xem mã thông báo có tồn tại không:

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

Nó kiểm tra xem "Mục" có tồn tại trong "Kết quả" không.

Đây là một ví dụ KHÔNG hoạt động gây ra ngoại lệ:

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

3

Bạn có thể chỉ cần gõ typecast và nó sẽ thực hiện chuyển đổi cho bạn, vd

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

Nó sẽ tự động quay trở lại nullnếu khóa nói không có trong đối tượng, vì vậy không cần phải kiểm tra nó.



1

Điều này quan tâm đến null

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

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

body?.SelectToken("path-double-prop")?.ToObject<double>();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.