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)
Comments are closed.