JContainer,JObject,JToken和Linq混淆

时间:2016-07-25 02:18:34

标签: c# json linq json.net

我无法理解何时使用JContainerJObjectJToken。我理解"标准" JObjectJProperties组成,JToken是所有JToken类型的基本抽象类,但我不理解JContainer

我正在使用C#而我刚买了LinqPad Pro 5.

我在文件中有一个JSON数据源,所以我使用这个语句成功地反序列化了该文件的内容:

string json;
using (StreamReader reader = new StreamReader(@"myjsonfile.json"))
{
    json = reader.ReadToEnd();
}

此时,我接受JSON字符串对象并将其反序列化为JObject(这可能是我的错误 - 也许我需要将jsonWork设为JToken或{ {1}}):

JContainer

在我的JSON数据(由JSON表示的字符串)中,我有三个对象 - 顶级对象看起来与此类似:

JObject jsonWork = (JObject)JsonConvert.DeserializeObject(json);

每个对象都由各种标记(数组,字符串,其他对象等)组成,因此它是动态JSON。 (我使用省略号作为占位符而不是用大量JSON数据混淆这个问题。)

但是,我想使用LINQ分别处理{ "Object1" : { ... }, "Object2" : { ... }, "Object3" : { ... } } "Object1""Object2"。所以,理想情况下,我想要这样的事情:

"Object3"

但上述行失败了。

我上面使用// these lines DO NOT work var jsonObject1 = jsonWork.Children()["Object1"] var jsonObject2 = jsonWork.Children()["Object2"] var jsonObject3 = jsonWork.Children()["Object3"] 因为我不知道我应该使用哪种对象类型:varJContainerJObject!只是让你知道我想要做什么,一旦正确分配了上述JToken变量,我想使用LINQ来查询它们包含的JSON。这是一个非常简单的例子:

jsonObject#

当然,我的LINQ最终将在var query = from p in jsonObject1 where p.Name == "Name1" select p 变量中过滤JSON数组,对象,字符串等。我想,一旦开始,我可以使用LinqPad帮助我使用LINQ过滤JSON。

我发现如果我使用:

jsonObject

然后我在// this line WORKS var jsonObject1 = ((JObject)jsonWork).["Object1"]; 中获得JObject类型。这是正确的方法吗?

我不清楚当jsonObject1JContainer对象看起来很好地使用LINQ时,/为什么会使用JTokenJObject的目的是什么?

3 个答案:

答案 0 :(得分:183)

在大多数情况下,您并不需要担心JContainer。它可以帮助组织和构建LINQ-to-JSON到代码良好的代码中。

JToken层次结构如下所示:

JToken             - abstract base class     
   JContainer      - abstract base class of JTokens that can contain other JTokens
       JArray      - represents a JSON array (contains an ordered list of JTokens)
       JObject     - represents a JSON object (contains a collection of JProperties)
       JProperty   - represents a JSON property (a name/JToken pair inside a JObject)
   JValue          - represents a primitive JSON value (string, number, boolean, null)

所以你看,JObject JContainer,其中 JToken

这是基本的经验法则:

  • 如果您知道自己有一个对象(在JSON中用花括号{}表示),请使用JObject
  • 如果您知道自己有数组或列表(用方括号[]表示),请使用JArray
  • 如果您知道自己有原始值,请使用JValue
  • 如果您不知道自己拥有哪种令牌,或希望能够以一般方式处理上述任何一种令牌,请使用JToken。然后,您可以检查其Type属性以确定它是什么类型的令牌并适当地投射它。

答案 1 :(得分:14)

JContainer是具有子项的JSON元素的基类。 JObjectJArrayJPropertyJConstructor都是从它继承的。

例如,以下代码:

(JObject)JsonConvert.DeserializeObject("[1, 2, 3]")

会抛出InvalidCastException,但是如果你将其投放到JContainer,那就没关系了。

关于您的原始问题,如果您知道顶层有JSON对象,则可以使用:

var jsonWork = JObject.Parse(json);
var jsonObject1 = o["Object1"];

答案 2 :(得分:0)

大多数示例都具有简单的json,并且我多次用Google搜索“ C#Newtonsoft解析JSON”。

这是我刚被要求解析为CSV的json文件的一部分。公司名称值嵌套在许多数组/对象中,因此在这方面它是半复杂的。

{
  "page": {
    "page": 1,
    "pageSize": 250
  },
  "dataRows": [
    {
      "columnValues": {
        "companyName": [
          {
            "name": "My Awesome Company",
          }
        ]
      }
    }
  ]
}
            var jsonFilePath = @"C:\data.json";
            var jsonStr = File.ReadAllText(jsonFilePath);

            // JObject implementation for getting dataRows JArray - in this case I find it simpler and more readable to use a dynamic cast (below)
            //JObject jsonObj = JsonConvert.DeserializeObject<JObject>(jsonStr);
            //var dataRows = (JArray)jsonObj["dataRows"];

            var dataRows = ((dynamic)JsonConvert.DeserializeObject(jsonStr)).dataRows;

            var csvLines = new List<string>();

            for (var i = 0; i < dataRows.Count; i++)
            {
                var name = dataRows[i]["columnValues"]["companyName"][0]["name"].ToString();

                // dynamic casting implemntation to get name - in this case, using JObject indexing (above) seems easier
                //var name2 = ((dynamic)((dynamic)((dynamic)dataRows[i]).columnValues).companyName[0]).name.ToString();

                csvLines.Add(name);
            }

            File.WriteAllLines($@"C:\data_{DateTime.Now.Ticks}.csv", csvLines);