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?
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With