无法使用Newtonsoft.Json.Linq反序列化对象;

时间:2015-12-23 21:11:42

标签: c# json.net

我收到这种格式的字符串:

   {
  "ok": true,
  "quote": { // the below is the same as returned through the REST quote API
    "symbol": "FAC",
    "venue": "OGEX",
    "bid": 5100, // best price currently bid for the stock
    "ask": 5125, // best price currently offered for the stock
    "bidSize": 392, // aggregate size of all orders at the best bid
    "askSize": 711, // aggregate size of all orders at the best ask
    "bidDepth": 2748, // aggregate size of *all bids*
    "askDepth": 2237, // aggregate size of *all asks*
    "last": 5125, // price of last trade
    "lastSize": 52, // quantity of last trade
    "lastTrade": "2015-07-13T05:38:17.33640392Z", // timestamp of last trade,
    "quoteTime": "2015-07-13T05:38:17.33640392Z" // server ts of quote generation
  }
}

出于性能原因,我想使用Newtonsoft.Json.Linq反序列化方法。当我尝试使用以下方法将Json字符串转换为Quote对象时:

 public static Quote QuoteFromJson(string quoteJson)
        {
            var json = JObject.Parse(quoteJson);
            var quote = json["quote"].
                Select(q => new Quote
                {
                    Ask = int.Parse(q["ask"].ToString()),
                    AskDepth = int.Parse(q["askDepth"].ToString()),
                    AskSize = int.Parse(q["askSize"].ToString()),
                    Bid = int.Parse(q["bid"].ToString()),
                    BidDepth = int.Parse(q["bidDepth"].ToString()),
                    BidSize = int.Parse(q["bidSize"].ToString()),
                    Last = int.Parse(q["last"].ToString()),
                    LastSize = int.Parse(q["lastSize"].ToString()),
                    LastTrade = q["lastTrade"].ToString(),
                    QuoteTime = q["quoteTime"].ToString(),
                    Symbol = q["symbol"].ToString(),
                }).First();

            return quote;
        }

这会显示错误消息:

Cannot access child value on Newtonsoft.Json.Linq.JProperty

我做错了什么?

2 个答案:

答案 0 :(得分:1)

以下是您问题的直接答案:

quote变量对应于JSON中的quote标记。这是一个单独的项目而不是集合,因此您不应将其视为集合并使用Select方法。

相反,请直接访问它:

var json = JObject.Parse(quoteJson);

var quote = json["quote"];

var result = new Quote
{
    Ask = int.Parse(quote["ask"].ToString()),
    AskDepth = int.Parse(quote["askDepth"].ToString()),
    AskSize = int.Parse(quote["askSize"].ToString()),
    Bid = int.Parse(quote["bid"].ToString()),
    BidDepth = int.Parse(quote["bidDepth"].ToString()),
    BidSize = int.Parse(quote["bidSize"].ToString()),
    Last = int.Parse(quote["last"].ToString()),
    LastSize = int.Parse(quote["lastSize"].ToString()),
    LastTrade = quote["lastTrade"].ToString(),
    QuoteTime = quote["quoteTime"].ToString(),
    Symbol = quote["symbol"].ToString(),
};

答案 1 :(得分:1)

您的问题是,您正在使用"quote"Select的子项进行迭代,然后按名称检索其属性。如果"quote"是一个数组,这是合适的,但它不是 - 它已经是一个单独的对象。因此你应该这样做:

        var rootObj = JObject.Parse(quoteJson);
        var quoteObj = rootObj["quote"];
        var quote = new Quote
        {
            Ask = (int)quoteObj["ask"],
            AskDepth = (int)quoteObj["askDepth"],
            AskSize = (int)quoteObj["askSize"],
            Bid = (int)quoteObj["bid"],
            BidDepth = (int)quoteObj["bidDepth"],
            BidSize = (int)quoteObj["bidSize"],
            Last = (int)quoteObj["last"],
            LastSize = (int)quoteObj["lastSize"],
            LastTrade = (string)quoteObj["lastTrade"],
            QuoteTime = (string)quoteObj["quoteTime"],
            Symbol = (string)quoteObj["symbol"],
        };

注意我正在使用explicit casting。这以与JSON standard一致的方式处理数字的国际化。 int.Parse()使用本地化格式进行解析,但不保证与所有语言环境中的标准一致。

但是,使用反序列化要简单得多:

        var rootObj = JObject.Parse(quoteJson);
        var quoteObj = rootObj["quote"];
        var quote = quoteObj.ToObject<Quote>();

我建议你应该花些时间来确保它真的比Linq慢到JSON。