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
。
JToken
是 JObject
、JArray
、JProperty
和 JValue
. 的抽象基础 class
JObject
是 JProperty
个对象的集合。 JObject
不能容纳任何其他种类的 JToken
.
JProperty
是一个名称-值对。名称始终是一个字符串,值可以是任何一种 JToken
除了另一个 JProperty
.
JArray
是 JToken
个对象的数组,除了 JProperty
.
JValue
表示 JSON 原始值。它可以包含字符串、数字、布尔值、日期或空值。请注意,JValue
与所有其他 JTokens 一样是引用类型。
以上 classes 旨在模拟 JSON spec。
现在让我们谈谈您在做什么以及您感到困惑的地方。
在您的代码中,您首先创建了一个 JObject。 JObject 包含一个名为 item
的 JProperty。 item
的值是另一个 JObject,它包含两个 JProperties,称为 foo
和 bar
。这些 JProperties 的值都是包含字符串的 JValues(分别为 4
和 42
)。
接下来,您使用 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";
我还没有注意到 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
。
JToken
是JObject
、JArray
、JProperty
和JValue
. 的抽象基础 class
JObject
是JProperty
个对象的集合。JObject
不能容纳任何其他种类的JToken
.JProperty
是一个名称-值对。名称始终是一个字符串,值可以是任何一种JToken
除了另一个JProperty
.JArray
是JToken
个对象的数组,除了JProperty
.JValue
表示 JSON 原始值。它可以包含字符串、数字、布尔值、日期或空值。请注意,JValue
与所有其他 JTokens 一样是引用类型。
以上 classes 旨在模拟 JSON spec。
现在让我们谈谈您在做什么以及您感到困惑的地方。
在您的代码中,您首先创建了一个 JObject。 JObject 包含一个名为 item
的 JProperty。 item
的值是另一个 JObject,它包含两个 JProperties,称为 foo
和 bar
。这些 JProperties 的值都是包含字符串的 JValues(分别为 4
和 42
)。
接下来,您使用 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";