Reputation: 33
Using the depreciated System.Json, I get the Result I expect (coming from Javascript): The Child gets a GrandChild and all the Parents know about it...
var Parents = new JsonObject();
var Children = new JsonObject();
var Parent = JsonArray.Parse("[]");
Parents.Add("1", Parent);
var Child = JsonArray.Parse("[]");
Children.Add("1", Child);
var DstParent = (JsonArray)Parents["1"];
DstParent.Add(Children["1"]);
var DstChild = (JsonArray)Children["1"];
JsonObject GrandChild = (JsonObject)JsonArray.Parse("{}");
GrandChild.Add("Age", 15);
DstChild.Add(GrandChild);
var Result = Parents.ToString();
Gives me: "{"1":[[{"Age":15}]]}"
Using Newtonsoft.Json 6.0.8, The Parent is not getting the "hint" that it's Child got a GrandChild.
var Parents = new JObject();
var Children = new JObject();
var Parent = JArray.Parse("[]");
Parents.Add("1", Parent);
var Child = JArray.Parse("[]");
Children.Add("1", Child);
var DstParent = (JArray)Parents["1"];
DstParent.Add(Children["1"]);
var DstChild = (JArray)Children["1"];
var GrandChild = JObject.Parse("{}");
GrandChild.Add("Age", 15);
DstChild.Add(GrandChild);
Gives me: "{"1":[[]]}"
What am I doing wrong?
Upvotes: 3
Views: 1246
Reputation: 117026
The problem arises because all JToken
objects have a Parent
property which records their location in the JSON object hierarchy -- but you are trying to add your JArray Child
to two different unrelated parents. First you add it to the Children
object (which is not actually in the tree of JSON objects you are creating):
Children.Add("1", Child);
Next you add it to the DstParent
array (which is in the tree of JSON objects you are creating):
DstParent.Add(Children["1"]);
So, what does Json.NET do in this case? It could either:
As it turns out, it takes option #3: it copies Children["1"]
into DstParent
. I'm not sure if or where this is documented, but it's apparent from the source code for JContainer
- look for InsertItem
which calls EnsureParentToken
. Thus when you add your grandchild to DstChild
you are adding it to the original array not the copy. You can see this by adding the following debug code:
Debug.WriteLine(object.ReferenceEquals(DstParent[0], DstChild)); //prints False
The simple fix for this is to avoid creating the Children
object which is completely unnecessary anyway:
var parentObj = new JObject();
var parentArray = new JArray();
parentObj.Add("1", parentArray);
var childArray = new JArray();
parentArray.Add(childArray);
var grandChild = new JObject();
grandChild.Add("Age", 15);
childArray.Add(grandChild);
Upvotes: 4