当我调用 JsonConvert.DeserializeObject() 时,为啥将 JArray 分配给 var 失败?

Posted

技术标签:

【中文标题】当我调用 JsonConvert.DeserializeObject() 时,为啥将 JArray 分配给 var 失败?【英文标题】:Why does assigning a JArray to a var fail when I call JsonConvert.DeserializeObject()?当我调用 JsonConvert.DeserializeObject() 时,为什么将 JArray 分配给 var 失败? 【发布时间】:2021-01-10 01:31:15 【问题描述】:

在这行代码上:

var arr = JsonConvert.DeserializeObject<JArray>(s);

...我得到了,“无法将类型为 'Newtonsoft.Json.Linq.JObject' 的对象转换为类型 'Newtonsoft.Json.Linq.JArray'。”

我把那行改成这样:

JArray arr = JsonConvert.DeserializeObject<JArray>(s);      

...并得到相同的错误消息。

我改成这样了:

var arr = JsonConvert.DeserializeObject<JObject>(s);

...它甚至无法编译。

此时调用(在字符串s中)读取的值是:

"id":347745,"results":["iso_3166_1":"US","release_dates":["certification":"","iso_639_1":"","note":"","release_date":"1936-12-12T00:00:00.000Z","type":3]]

我想要的只是“认证”的价值;在这种情况下,认证值是一个空字符串(“certification”:“”)

在上下文中,代码是:

. . .
try

    var webRequest = (HttpWebRequest)WebRequest.Create(RESTStringToGetMPAARatingForMovieId);
    webRequest.Method = "GET";  
    var webResponse = (HttpWebResponse)webRequest.GetResponse();
    if ((webResponse.StatusCode == HttpStatusCode.OK) && (webResponse.ContentLength > 0))
    
        StreamReader streamReader = new StreamReader(webResponse.GetResponseStream());
        string s = streamReader.ReadToEnd();
        var arr = JsonConvert.DeserializeObject<JArray>(s);
        //JArray arr = JsonConvert.DeserializeObject<JArray>(s);
        //var arr = JsonConvert.DeserializeObject<JObject>(s);
        foreach (JObject obj in arr)
        
            _currentMPAARating = (string)obj["certification"];
            . . .
        
    
    else
    
        MessageBox.Show(string.Format("Status code == 0, Content length == 1",
          webResponse.StatusCode, webResponse.ContentLength));
        

catch (Exception ex)

    MessageBox.Show(ex.Message);

【问题讨论】:

【参考方案1】:

您的 JSON 不是一个数组,它是一个包含一个数组的对象 (results)。但实际上比这更复杂:您寻找的certification 字符串嵌套在第二个release_dates 数组中。

如果您获取 JSON 并使用 JSON 验证器/美化器重新格式化它,它应该会变得更加清晰:


  "id": 347745,
  "results": [
    
      "iso_3166_1": "US",
      "release_dates": [
        
          "certification": "",
          "iso_639_1": "",
          "note": "",
          "release_date": "1936-12-12T00:00:00Z",
          "type": 3
        
      ]
    
  ]

因此,要使用常规 foreach 循环获取您要查找的数据,您需要如下代码:

var obj = JsonConvert.DeserializeObject<JObject>(s);
var resultArr = (JArray)obj["results"];
foreach (JObject resultObj in resultArr)

    var releaseDatesArr = (JArray)resultObj["release_dates"];
    foreach (JObject releaseDateObj in releaseDatesArr)
    
        _currentMPAARating = (string)releaseDateObj["certification"];
        // ...
    

小提琴:https://dotnetfiddle.net/SMzQTw

如果您只需要一个项目,这里有一个快捷方式。使用带有递归下降运算符 (..) 的 SelectToken 方法,如下所示:

var obj = JsonConvert.DeserializeObject<JObject>(s);
_currentMPAARating = (string)obj.SelectToken("..certification");

小提琴:https://dotnetfiddle.net/S1ScLO

但请注意,上面只会返回第一个匹配项。如果您希望获得多个认证,则可以改用 SelectTokens(复数):

var obj = JsonConvert.DeserializeObject<JObject>(s);
var ratings = obj.SelectTokens("..certification").Select(t => (string)t).ToList();

小提琴:https://dotnetfiddle.net/zyjNnJ

【讨论】:

这看起来就像锯骨所订购的那样,但是“..certification”中的这两个点真的是字面意思吗? 是的,两个点是递归下降运算符。完全需要它们,如代码所示。 我在答案中添加了一个小提琴来演示。 谢谢;让它工作!我会尽快为您提供答案。如果您也想看一下,我刚刚发布了另一个:***.com/questions/64036948/… 如果返回的json包含多个“certification”值,上面的代码是不是只取第一个?例如,返回的子集可以是:""id":78,"results":["iso_3166_1":"US","re​​lease_dates":["certification":"R","iso_639_1 ":"","note":"","re​​lease_date":"1982-06-25T00:00:00.000Z","type":3],"iso_3166_1":"FI","re​​lease_dates" :["certification":"K-16","iso_639_1":"","note":"","re​​lease_date":"1982-10-01T00:00:00.000Z","type":3 ]”,这只是一个子集——在返回的内容中大约有数以亿计的“认证”

以上是关于当我调用 JsonConvert.DeserializeObject() 时,为啥将 JArray 分配给 var 失败?的主要内容,如果未能解决你的问题,请参考以下文章

当我使用 curl 命令调用服务时出现异常“UT000004:getResponseChannel() 已被调用”

当我调用一个简单的函数时,析构函数被调用

com.netflix.zuul.exception.ZuulException:当我调用 POST 方法调用时出现转发错误

当我从另一个类调用数组时,数组不会更新

当我调用 fseek() 时,在低级别会发生啥?

当我将构造函数作为参数显式调用时,不会调用移动构造函数