0

With JsonValueKind.Object you can use:

value.GetProperty("XXX")

With JsonValueKind.Array you can use:

value.EnumerateArray().ElementAtOrDefault(2)

But is it also possible to get a specific index without enumerating the array?

The reason is that this is called in a tight loop.

I could read all values and cache them in a dictionary myself, but as I read that System.Text.Json is specifically made for performance I don't want to allocate unnecessary dictionaries.

Here's an example.

static void Main(string[] args)
{
    var json = JsonSerializer.Deserialize<JsonElement>(@"[ ""item1"", ""item2""]");

    // (seems) to enumerate the whole object - so slow in loops with large arrays
    var test1 = json.EnumerateArray().ElementAtOrDefault(1);

    // FIXME: crashes
    var test2 = json.GetProperty("1");

    // would love to have (return null when not existing - does not enumerate array - dictionary-like performance)
    // var test3 = json.GetElementAt("1"); 
}

Note that

  • the actual code is called in a tight loop - it needs close to O(1) performnce
  • the array can be quite large (not just two elements)
Dirk Boer
  • 8,522
  • 13
  • 63
  • 111
  • Please, share the appropriate code – Pavel Anikhouski May 04 '20 at 10:08
  • [`ArrayEnumerator`](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement.arrayenumerator?view=netcore-3.1) implements `IEnumerable`, you can cast to list or use linq to get any element, as you've already done – Pavel Anikhouski May 04 '20 at 10:50
  • Hi @PavelAnikhouski, see the question - in theory I can do that, but as the System.Text.Json is specifically designed for performance I would rather prevent this if it's necessary - saving an extra dictionary allocation. – Dirk Boer May 04 '20 at 10:51
  • Not sure you can. If you look at the reference source, `JsonDocument` contains [a `ReadOnlyMemory _utf8Json;` field and a `MetadataDb parsedData` field](https://github.com/dotnet/runtime/blob/3b36f9836642d9c460a803bb84e52468d281da75/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.cs#L27). And [`MetadataDb`](https://github.com/dotnet/runtime/blob/3b36f9836642d9c460a803bb84e52468d281da75/src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs) seems to basically be metadata about where to find properties and elements in the JSON. – dbc May 08 '20 at 18:13
  • So, unlike LINQ to JSON there doesn't seem to be some immediately accessible `List` of array items, instead we can enumerate through the array items by enumerating through the metadata and using it to access items in the raw JSON as needed. (Could be wrong, I've only scanned the code not reviewed it in detail.) – dbc May 08 '20 at 18:15
  • You can get direct access to the value at a specific index, using the indexer on JsonElement (so for example `value[2]`). However, it won't always be O(1), and that is the side effect of the non-allocating design. @DirkBoer - let me know if this answers your question. https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement.item?view=netcore-3.1#System_Text_Json_JsonElement_Item_System_Int32_ – ahsonkhan May 14 '20 at 23:18

0 Answers0