从可能不存在的 JToken 中获取价值(最佳实践)

Posted

技术标签:

【中文标题】从可能不存在的 JToken 中获取价值(最佳实践)【英文标题】:Get value from JToken that may not exist (best practices) 【发布时间】:2012-03-24 06:10:20 【问题描述】:

使用 Json.NET 检索 C# 中可能不存在的 JSON 值的最佳做法是什么?

现在,我正在处理一个 JSON 提供程序,它返回的 JSON 有时包含某些键/值对,有时不包含。我一直在使用(可能是错误的)这种方法来获取我的值(获取双精度值的示例):

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

现在效果很好,但是当它们很多时,它很麻烦。我最终写了一个扩展方法,只有 写完之后我才想知道我是不是很愚蠢......无论如何,这是扩展方法(我只包括双精度和字符串的情况,但是实际上我还有很多):

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

顺便说一句,请原谅可能是一个非常愚蠢的问题,因为它似乎应该有一个内置函数......我确实尝试过谷歌和Json.NET文档,但是我要么无能为力找到我的问题的解决方案,或者在文档中不清楚。

【问题讨论】:

我知道有点晚了,但你可能想试试下面这个简化版的GetValue string rootValue = jToken.Value&lt;string&gt;() 【参考方案1】:

这几乎就是通用方法Value() 的用途。如果将它与可为空的值类型和 ?? 运算符结合使用,您将得到您想要的行为:

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

【讨论】:

@PaulHazen,还不错……你只是重新发明了***而已。 如果 json 中不存在“width”且 JToken 为 null,则此方法不起作用 @Deepak 如果“宽度”不存在,它确实有效。当然,如果jTokennull,它就不起作用,但这不是问题所要问的。您可以使用 null 条件运算符轻松解决此问题:width = jToken?.Value&lt;double?&gt;("width") ?? 100; JToken.Value&lt;T&gt; 如果 JToken 是 JValue 则抛出异常 处理套管:string ver = ((JObject)token).GetValue("version", StringComparison.OrdinalIgnoreCase)?.Value&lt;string&gt;(); ***.com/a/49886682/2874896【参考方案2】:

我会写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),所以我倾向于将所有解析保存在一个地方,并保持简单(其中一部分也是返回给我的数据的不可预测性)。 @PaulHazen 我不能说我理解你。你的问题是retrieving JSON values that may not even exist,我提出的只是改变你的GetValue 方法。我认为它可以按照您的意愿工作 希望这次我能更清楚一点。您的方法效果很好,并且完全可以完成我想要的。但是,我的问题中没有解释的更大背景是,我正在处理的特定代码是我希望高度可转移的代码。虽然有争议的是您的方法会妨碍您,但它引入了从 GetValue 反序列化对象的能力,这是我想避免的一种模式,以便将我的代码移动到具有更好 JSON 解析器的平台(比如, 以 Win8 为例)。所以,按照我的要求,是的,你的代码会很完美。【参考方案3】:

您可以通过以下方式检查令牌是否存在:

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

它检查“结果”中是否存在“项目”。

这是导致异常的无效示例:

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

【讨论】:

【参考方案4】:

您可以简单地进行类型转换,它会为您进行转换,例如

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

如果对象中不存在该键,它将自动返回null,因此无需对其进行测试。

【讨论】:

【参考方案5】:

这会处理空值

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

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

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

【讨论】:

【参考方案6】:

TYPE variable = jsonbody["key"]?.Value&lt;TYPE&gt;() ?? DEFAULT_VALUE;

例如

bool attachMap = jsonbody["map"]?.Value&lt;bool&gt;() ?? false;

【讨论】:

以上是关于从可能不存在的 JToken 中获取价值(最佳实践)的主要内容,如果未能解决你的问题,请参考以下文章

按索引从 Collection 中获取价值的最佳方式

最佳实践 - 根据状态操作,这样能避免吃掉异常

Tensorflow:从问题中获取手册的一部分的最佳实践是啥?

如何使用 JSON 路径获取 JSON 字符串的一部分而不是 JToken?

从python中的html获取价值的最佳方法? [复制]

价值回报方法JPQL的最佳实践