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] = 4Code language: plaintext (plaintext)

Comments are closed.