JToken 不是 JObject 的引用?

JToken is not a reference of JObject?

我还没有注意到 James Newton King 写过或谈到过 JToken is。我错误地假设它以某种方式持有对 JObject 的引用。事实并非如此,因为这些 LINQPad 语句表明:

var json = @"
{
    ""item"": {
        ""foo"": ""4"",
        ""bar"": ""42""
    }
}
";

var jO = JObject.Parse(json);
var jToken = jO["item"]["foo"];

jToken = "5";

jO.ToString().Dump("jO");

jToken.Dump("jToken");

输出:

jO
{
  "item": {
    "foo": "4",
    "bar": "42"
  }
}

jToken
5 

不应该jO["item"]["foo"] == 5吗?

首先,让我们谈谈什么是JToken

  • JTokenJObjectJArrayJPropertyJValue.
  • 的抽象基础 class
  • JObjectJProperty 个对象的集合。 JObject 不能容纳任何其他种类的 JToken.
  • JProperty 是一个名称-值对。名称始终是一个字符串,值可以是任何一种 JToken 除了另一个 JProperty.
  • JArrayJToken 个对象的数组,除了 JProperty.
  • JValue 表示 JSON 原始值。它可以包含字符串、数字、布尔值、日期或空值。请注意,JValue 与所有其他 JTokens 一样是引用类型。

以上 classes 旨在模拟 JSON spec

现在让我们谈谈您在做什么以及您感到困惑的地方。

在您的代码中,您首先创建了一个 JObject。 JObject 包含一个名为 item 的 JProperty。 item 的值是另一个 JObject,它包含两个 JProperties,称为 foobar。这些 JProperties 的值都是包含字符串的 JValues(分别为 442)。

接下来,您使用 JToken 索引器语法获取对 foo JProperty 的 value 的引用(一个包含字符串值 4) 并将该引用分配给您的 jToken 变量。请注意,此变量的声明类型是 JToken,尽管此处值的实际类型实际上是 JValue。 (如果你这样做,你可以看到这个 jToken.GetType().Name.Dump("jToken type")

到目前为止和我在一起吗?

好的,这就是我认为您感到困惑的地方。 JToken 提供隐式和显式转换,允许从各种 .NET 基元分配或强制转换它。如果您执行 jToken = "5",那实际上与 jToken = new JValue("5") 的意思相同。因此,您所做的是用对包含 5 的不同 JValue 的新引用替换 jToken 变量(对包含 4 的 JValue)的引用。这显然不会对原始 JObject 产生影响。

如果您试图修改原始 JValue 的值,则需要将您的 jToken 转换为 JValue,然后使用 Value setter 进行设置。

((JValue)jToken).Value = "5";

Fiddle: https://dotnetfiddle.net/StIGxM

实际上 JToken 有一个对其父级的引用(检查 Parent 属性)。
回到您的示例 - 在这一行 jToken = "5"; 中,您正在创建新的 JToken(更具体地说,字符串被隐式转换为 JValue)。基本上它与 jToken = new JValue("5"); 相同,所以变量 jToken 现在指向全新的 JValue。这解释了为什么更改未反映在原始 JObject.
中 要修复您的示例,请使用:((JValue)jToken).Value = "5";