C# – Serialize and deserialize a multidimensional array to JSON

System.Text.Json doesn’t support serializing / deserializing multidimensional arrays. When you try, it throws an exception like this – System.NotSupportedException: The type ‘System.Int[,] is not supported.

You have three options:

  • Use Newtonsoft.Json instead. It supports multidimensional arrays.
  • Use a jagged array (i.e. int[][]) instead. System.Text.Json supports these.
  • Write a custom JsonConverter that handles multidimensional arrays.

In this article, I’ll show an example of how to create a custom JsonConverter that handles multidimensional arrays. In this example, I’ll specifically show how to serialize / deserialize a two-dimensional integer array.

1 – Create custom JsonConverter class

The first step is to create a class that implements JsonConverter<int[,]>.

using System.Text.Json.Serialization; using System.Text.Json; public class TwoDimensionalIntArrayJsonConverter : JsonConverter<int[,]> { public override int[,]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotImplementedException(); } public override void Write(Utf8JsonWriter writer, int[,] value, JsonSerializerOptions options) { throw new NotImplementedException(); } }
Code language: C# (cs)

There are two methods to implement: Write() for serializing and Read() for deserializing.

2 – Serialize a multidimensional array in JsonConverter.Write()

We’ll serialize the multidimensional array in the Write() method by looping through its dimensions and writing it as an array of arrays. To write a JSON array:

  • Start the array with writer.WriteStartArray().
  • Use writer.WriteNumberValue() to write each integer to the array.
  • Close the array with writer.WriteEndArray().

Here’s how to implement the Write() method (highlighted):

using System.Text.Json.Serialization; using System.Text.Json; public class TwoDimensionalIntArrayJsonConverter : JsonConverter<int[,]> { public override void Write(Utf8JsonWriter writer, int[,] value, JsonSerializerOptions options) { writer.WriteStartArray(); for (int i = 0; i < value.GetLength(0); i++) { writer.WriteStartArray(); for (int j = 0; j < value.GetLength(1); j++) { writer.WriteNumberValue(value[i, j]); } writer.WriteEndArray(); } writer.WriteEndArray(); } public override int[,]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { throw new NotImplementedException(); } }
Code language: C# (cs)

3 – Deserialize to multidimensaionl array in JsonConverter.Read()

When we serialized the two-dimensional array in the Write() method, we wrote it as a JSON array of arrays. It looks like this:

[[1,2],[3,4]]
Code language: JSON / JSON with Comments (json)

We’ll deserialize this JSON array of arrays to a two-dimensional integer array in the Read() method in two steps:

  • Initialize the two-dimensional array with the correct dimension sizes. This is tricky with Utf8JsonReader because it’s a forward-only reader. Instead, we can use JsonDocument to get the lengths of the outer array and first nested array.
  • Loop through the nested arrays, read the integer values, and add the values to the two-dimensional array.

Here’s how to implement the Read() method (highlighted):

using System.Text.Json.Serialization; using System.Text.Json; using System.Linq; public class TwoDimensionalIntArrayJsonConverter : JsonConverter<int[,]> { public override int[,]? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var jsonDoc = JsonDocument.ParseValue(ref reader); var rowLength = jsonDoc.RootElement.GetArrayLength(); var columnLength = jsonDoc.RootElement.EnumerateArray().First().GetArrayLength(); int[,] grid = new int[rowLength, columnLength]; int row = 0; foreach (var array in jsonDoc.RootElement.EnumerateArray()) { int column = 0; foreach (var number in array.EnumerateArray()) { grid[row, column] = number.GetInt32(); column++; } row++; } return grid; } public override void Write(Utf8JsonWriter writer, int[,] value, JsonSerializerOptions options) { writer.WriteStartArray(); for (int i = 0; i < value.GetLength(0); i++) { writer.WriteStartArray(); for (int j = 0; j < value.GetLength(1); j++) { writer.WriteNumberValue(value[i, j]); } writer.WriteEndArray(); } writer.WriteEndArray(); } }
Code language: C# (cs)

Note: Using foreach with EnumerateArray() has the same performance as a regular for loop and is easier to read.

4 – Use the custom JsonConverter

To use the custom JsonConverter, add it to JsonSerializerOptions.Converters. It’ll be used when you serialize / deserialize with this options object. Here’s an example of using the custom converter we created above:

using System.Text.Json; int[,] grid = new int[,] { { 1, 2 }, { 3, 4 } }; var options = new JsonSerializerOptions(); options.Converters.Add(new TwoDimensionalIntArrayJsonConverter()); var json = JsonSerializer.Serialize(grid, options); Console.WriteLine($"Serialized: {json}"); var gridFromJson = JsonSerializer.Deserialize<int[,]>(json, options); Console.WriteLine("Deserialized:"); Console.WriteLine($"[0,0] = {gridFromJson[0,0]}"); Console.WriteLine($"[0,1] = {gridFromJson[0,1]}"); Console.WriteLine($"[1,0] = {gridFromJson[1,0]}"); Console.WriteLine($"[1,1] = {gridFromJson[1,1]}");
Code language: C# (cs)

This outputs the following, showing that serialization and deserialization worked as expected:

Serialized: [[1,2],[3,4]] Deserialized: [0,0] = 1 [0,1] = 2 [1,0] = 3 [1,1] = 4
Code language: plaintext (plaintext)

Leave a Comment