Search code examples
c#json.net-6.0system.text.json

Idiom for removing a JsonNode?


I am trying to modify an in memory JsonNode instance. Minimal reproducible code is simply (.NET Fiddle):

        string jsonString =
            @"{
  ""Date"": ""2019-08-01T00:00:00"",
  ""Temperature"": 25,
  ""Summary"": ""Hot"",
  ""DatesAvailable"": [
    ""2019-08-01T00:00:00"",
    ""2019-08-02T00:00:00""
  ],
  ""TemperatureRanges"": {
      ""Cold"": {
          ""High"": 20,
          ""Low"": -10
      },
      ""Hot"": {
          ""High"": 60,
          ""Low"": 20
      }
  }
}
";
        JsonNode jDataSet = JsonNode.Parse(jsonString)!;
        var dataSet = jDataSet.AsObject();
        foreach (var entry in dataSet)
        {
            if (entry.Key == "TemperatureRanges")
            {
                entry.Value.AsObject().Remove("Hot");
            }
            else if (entry.Key == "Date")
            {
                dataSet.Remove(entry.Key); // boom !
            }
        }

Obviously this is the wrong approach (as seen with other structure here), how should I re-write the above code to handle removal of JsonNode in my case ?

Current code trigger:

System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
   at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
   at System.Collections.Generic.List`1.Enumerator.MoveNext()
   at System.Text.Json.JsonPropertyDictionary`1.GetEnumerator()+MoveNext()
   at Tests.UnitTest1.Test2() in C:\Users\malat\project\tests\Tests\UnitTest1.cs:line 43

Using:

> dotnet --version
6.0.408

Fundamentally my question is identical to this one but for JsonNode.


Solution

  • Three options present themselves:

    • Call ToList() to create a sequence to iterate over that won't be modified by calling Remove:

      foreach (var entry in dataSet.ToList())
      

      That's somewhat inefficient of course - whether that's a problem or not for you will depend on your app.

    • Don't do the removal in the loop, but keep a list of keys you want to remove after iterating over dataSet.

    • Don't bother keeping a list - just unconditionally call dataSet.Remove("Date") after the loop. (In your example at least, you know the key you want to remove - and Remove doesn't throw an exception if the key is missing anyway.)