0

I've read here Is the order of elements in a JSON list preserved?

that the order in Json matters.

I've also read here Does List<T> guarantee insertion order? that the insert order in a C# generic list is guaranteed.

Can I therefor assume that when I use the newtonsoft JsonSerializer to read this Json

 "answers": [
            {
                "choice": "36"
            },
            {
                "choice": "50"
            }
        ]

in an object with a property 'Answers' which is of type GenericList, that Answers[0] always returns 36 and Answers[1] always returns 50?

Or is it possible the JsonSerializer shuffles data around?

The reason I ask is that I read data from an external API and they say "you should only get 1 answer back, but when you get more, use the last one", and the last is the last one in text, so in this case the '50'.

Michel
  • 23,085
  • 46
  • 152
  • 242
  • 1
    Json.NET will not shuffle the order of elements when deserializing a type implementing `IList` or `IList` including `List` or any array. It inserts them into lists (or collections) in the order they are encountered There is some weird problem with `Stack` getting reversed as explained [here](https://stackoverflow.com/q/39137123) but that's really the only such example and is due to `Stack`'s slightly idiosyncratic implementation, namely that the enumerator reverses the order of items passed to the constructor. Is this the sort of answer you want, or do you need doc/source links? – dbc Sep 18 '18 at 07:38
  • Given the amount of answers you gave on this site I tend to believe that you know the details of the JsonSerializer. Is that from your own experiences or do you know sourcecode? – Michel Sep 18 '18 at 10:32
  • 1
    (Goes to check) For read/write collections you can see the details in [`JsonSerializerInternalReader.PopulateList()`](https://github.com/JamesNK/Newtonsoft.Json/blob/master/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs#L1569). Of course the underlying collection might rearrange the items, imaging populating a `SortedSet` for example. – dbc Sep 18 '18 at 10:49
  • Nice. Never thought of looking up the code to check for myself. Good one. Convinced now! – Michel Sep 19 '18 at 06:03

1 Answers1

1

Yes, you can rely on the order of array nodes read via the JsonSerializer. A JSON array is defined to be an ordered collection of values., and Json.NET will add them to your collection in the order they are encountered in the JSON file.

This can be verified by checking the source code. The method JsonSerializerInternalReader.CreateList() is the top-level method responsible for collection deserialization, and has three basic cases:

  1. When deserializing to a read/write collection, ICollection.Add() (or ICollection<T>.Add()) will get called in the order in which values are read from the JSON stream, thereby preserving the JSON array order. This can be seen in JsonSerializerInternalReader.PopulateList().

    (When the collection is missing a non-generic Add(object value) method, a CollectionWrapper<T> will get created to handle casting to the required argument type, however this does not affect the algorithm at all since the wrapper immediately calls the Add(T Value) method of the underlying collection.)

  2. When deserializing to a .Net array, a temporary List<T> is created for some appropriate T and values are added in the order encountered as in case 1, either through JsonSerializerInternalReader.PopulateList() or JsonSerializerInternalReader.PopulateMultidimensionalArray(). Subsequently the list is converted to an array afterwards by calling either Array.CreateInstance then List<T>.ICollection.CopyTo(Array, Int32), or CollectionUtils.ToMultidimensionalArray(). Both create the array preserving the order of values of the incoming collection.

  3. When deserializing an immutable collection, the collection must have a constructor that takes an IEnumerable<T> where T is the collection item type. This is explained in the release notes for Json.NET 6.0.3:

    To all future creators of immutable .NET collections: If your collection of T has a constructor that takes IEnumerable<T> then Json.NET will automatically work when deserializing to your collection, otherwise you're all out of luck.

    Assuming your immutable collection has the required constructor, the algorithm proceeds as in case 2, deserializing to a List<T> then constructing the immutable collection from the list with the values in the order they were encountered and deserialized.

Of course, the collection itself might shuffle the order of values:

However for the basic collections List<T> or T [] this will not occur.

dbc
  • 104,963
  • 20
  • 228
  • 340