json.net - newtonsoft - JToken no es una referencia de JObject?
linq to json (2)
Todavía no me he dado cuenta de que James Newton King escribió o habló sobre lo que es JToken
. He hecho la suposición incorrecta de que de alguna manera contiene una referencia a JObject
. Este no es el caso ya que estas declaraciones de LINQPad demuestran:
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");
La salida:
jO
{
"item": {
"foo": "4",
"bar": "42"
}
}
jToken
5
¿No debería jO["item"]["foo"] == 5
?
En realidad, JToken
tiene una referencia a su padre (ver propiedad Parent
).
Volviendo a su ejemplo, en esta línea jToken = "5";
está creando un nuevo JToken
(para ser más específico, la cadena se convierte implícitamente en JValue
). Básicamente es lo mismo que jToken = new JValue("5");
Entonces, la variable jToken
ahora apunta a un nuevo JValue
. Esto explica por qué el cambio no se refleja en JObject
original.
Para corregir su ejemplo, use: ((JValue)jToken).Value = "5";
Primero, hablemos de lo que es un JToken
.
-
JToken
es la clase base abstracta paraJObject
,JArray
,JProperty
yJValue
. -
JObject
es una colección de objetosJProperty
. UnJObject
no puede contener ningún otro tipo deJToken
. -
JProperty
es un par nombre-valor. El nombre siempre es una cadena, y el valor puede ser cualquier tipo deJToken
excepto otroJProperty
. -
JArray
es una matriz de objetosJToken
de cualquier tipo exceptoJProperty
. -
JValue
representa un valor primitivo JSON. Puede contener una cadena, número, booleano, fecha o nulo. Tenga en cuenta queJValue
es un tipo de referencia como todos los demás JTokens.
Las clases anteriores están destinadas a modelar la especificación JSON .
Ahora hablemos de lo que está haciendo y de dónde se confunde.
En su código, primero está creando un JObject. El JObject contiene un artículo llamado JProperty. El valor del item
es otro JObject que contiene dos JProperties, llamadas foo
y bar
. Los valores de estas JProperties son ambos JValues que contienen cadenas ( 4
y 42
, respectivamente).
A continuación, usa la sintaxis del indexador JToken para obtener una referencia al valor de foo
JProperty (un JValue que contiene el valor de cadena 4
) y asigne esa referencia a su variable jToken
. Tenga en cuenta que el tipo declarado de esta variable es JToken, aunque el tipo real del valor aquí es de hecho JValue. (Puede ver esto si lo hace jToken.GetType().Name.Dump("jToken type")
)
Conmigo hasta ahora?
OK, aquí es donde creo que te estás confundiendo. JToken proporciona conversiones implícitas y explícitas que permiten su asignación o conversión a varias primitivas .NET. Si haces jToken = "5"
eso realmente significa lo mismo que jToken = new JValue("5")
. Entonces, lo que ha hecho es reemplazar la referencia que tenía su variable jToken
(al JValue que contiene 4
) con una nueva referencia a un JValue diferente que contiene 5
. Obviamente, esto no tendrá ningún efecto en el JObject original.
Si está intentando modificar el valor del JValue original, debe convertir su jToken
a JValue y luego usar el Value
setter para establecerlo.
((JValue)jToken).Value = "5";
Fiddle: https://dotnetfiddle.net/StIGxM