C# Linq JSON nested arrays strange behaviour

Viewed 166

I've been trying to create nested arrays with C# Linq JSON library. Is there some reason why first way doesn't work but later one works.

using System;
using Newtonsoft.Json.Linq;

public class Program
{
    public static void Main()
    {       
        JObject jo = new JObject();

        // Linq-way
        jo.Add(new JProperty("Nested_failed", new JArray(
            new JArray(
                new JValue(0),
                new JValue(false),
                new JValue(21)
                    )
                )
            )
        );

        // Second try
        JArray nested = new JArray();
        nested.Add(new JArray(
            new JValue(0), 
            new JValue(false), 
            new JValue(21)
            )
        );
        jo.Add(new JProperty("Nested_succeed",nested));

        Console.WriteLine(jo.ToString());   
    }
}

Results this

{
  "Nested_failed": [
    0,
    false,
    21
  ],
  "Nested_succeed": [
    [
      0,
      false,
      21
    ]
  ]
}

As far as I can understand, both ways should end up to the same result. But for some reason nested JArray is skipped when you construct it in "Linq-way".

2 Answers

It comes down to the constructors of `JArray'.

    // Linq-way
    jo.Add(new JProperty("Nested_failed", new JArray(
        new JArray(
            new JValue(0),
            new JValue(false),
            new JValue(21)
                )
            )
        )
    );

In your first example above, you are creating a JArray from an existing JArray. The documentation provides the following signature for the constructor that is being chosen in this case:

public JArray(JArray other)

And of other, states:

A JArray object to copy from.

So this creates a new JArray as a copy of an existing one. It doesn't create a nested array.

There are other constructors on JArray that do create a new one (JArray(Object content) and JArray(params Object[] content)), so you could force your code to use the second constructor I mentioned above by adding a cast to (object):

    // Linq-way
    jo.Add(new JProperty("Nested_failed", new JArray(
        (object)new JArray(
            new JValue(0),
            new JValue(false),
            new JValue(21)
                )
            )
        )
    );

You should update the failed part a little bit and pass nested JArray to collection initializer of outer JArray

jo.Add(new JProperty("Nested_failed", 
    new JArray
    {
        new JArray(new JValue(0), new JValue(false), new JValue(21))
    }
));

JArray ctor accept a parameter, which is used to copy values from, not for adding it as a nested value

Initializes a new instance of the JArray class from another JArray object.

Parameters

other

Type: Newtonsoft.Json.Linq.JArray

A JArray object to copy from.

After adding an collection initializer you'll get the following output, which is the same with the second try

  "Nested_failed": [
    [
      0,
      false,
      21
    ]
  ],
  "Nested_succeed": [
    [
      0,
      false,
      21
    ]
  ]
}
Related