JRaw SelectToken返回null

时间:2018-10-20 11:53:47

标签: c# json.net

我正在.Net core 2.0中使用Newtonsoft.Json 11.0.2。

如果我使用JObject,则可以像这样SelectToken

JObject.Parse("{\"context\":{\"id\":42}}").SelectToken("context.id")

返回

  

42

但是,如果我使用JRaw,则对于同一路径,我会得到null吗?

new JRaw("{\"context\":{\"id\":42}}").SelectToken("context.id")

返回

  

由于代码的设置方式,我的模型已经在JRaw中,并将其转换为JObject以选择该令牌似乎是对RAM的浪费(此调用位于热路径上)。

更新 好的,我的实际数据归结到一个模型中,其中只有一个属性是JRaw,所以我需要像下面这样的东西来工作:

 JsonConvert.DeserializeObject<Dictionary<string, JRaw>>(
 "{\"a\":{\"context\":{\"id\":42}}}")["a"].SelectToken("context.id")

以上内容再次返回null。

1 个答案:

答案 0 :(得分:1)

标题可能有点误导,但是OP基本上需要的是一种在不占用过多内存的情况下解析现有(大型)JRaw对象的方法。

我进行了一些测试,并且能够使用JsonTextReader找到解决方案。

我不知道OP的json字符串的确切结构,所以我假设是这样的:

[
  {
    "context": {
      "id": 10
    }
  },
  {
    "context": {
      "id": 20
    }
  },
  {
    "context": {
      "id": 30
    }
  }
]

结果将是具有id值(10、20、30)的整数数组。

解析方法

因此,该方法采用JRaw对象作为参数,并使用JsonTextReader提取ID。

private static IEnumerable<int> GetIds(JRaw raw)
{
    using (var stringReader = new StringReader(raw.Value.ToString()))
    using (var textReader = new JsonTextReader(stringReader))
    {
        while (textReader.Read())
        {
            if (textReader.TokenType == JsonToken.PropertyName && textReader.Value.Equals("id"))
            {
                int? id = textReader.ReadAsInt32();

                if (id.HasValue)
                {
                    yield return id.Value;
                }
            }
        }
    }
}

在上面的示例中,我假设只有一种类型的对象具有id属性。

还有其他方法可以提取我们需要的信息,例如我们可以检查令牌类型和路径,如下所示:

if (textReader.TokenType == JsonToken.Integer && textReader.Path.EndsWith("context.id"))
{
    int id = Convert.ToInt32(textReader.Value);
    yield return id;
}

测试代码

出于测试目的,我创建了与上述json结构匹配的以下C#类:

public class Data
{
    [JsonProperty("context")]
    public Context Context { get; set; }

    public Data(int id)
    {
        Context = new Context
        {
            Id = id
        };
    }
}

public class Context
{
    [JsonProperty("id")]
    public int Id { get; set; }
}

创建JRaw对象并提取ID:

class Program
{
    static void Main(string[] args)
    {
        JRaw rawJson = CreateRawJson(); 
        List<int> ids = GetIds(rawJson).ToList(); 

        Console.Read();
    }

    //  Instantiates 1 million Data objects and then creates a JRaw object
    private static JRaw CreateRawJson()
    {
        var data = new List<Data>();

        for (int i = 1; i <= 1_000_000; i++)
        {
            data.Add(new Data(i));
        }

        string json = JsonConvert.SerializeObject(data);

        return new JRaw(json);
    }
}

内存使用情况

我使用Visual Studio的诊断工具拍摄了以下快照,以检查内存使用情况:

Memory Usage screenshot

  • 快照1是在控制台应用程序的开头拍摄的(预期内存不足)
  • 快照2是在创建JRaw对象之后拍摄的
      

    JRaw rawJson = CreateRawJson();

  • 快照3是在提取ID之后拍摄的
      

    列表ID = GetIds(rawJson).ToList();

相关问题