Serialize a tuple to JSON in C#

By FoxLearn 2/5/2025 8:08:55 AM   143
When you serialize a tuple to JSON, the underlying ValueTuple field names, Item1 and Item2, are used. This is true even if you are using a named tuple. The field names you specify in the tuple declaration won't be reflected in the JSON.

Both Newtonsoft and System.Text.Json exhibit this behavior.

Serializing with Newtonsoft

using Newtonsoft.Json;

var namedTuple = (product: "Laptop", price: 999.99);
var namedTupleJSON = JsonConvert.SerializeObject(namedTuple);

Console.WriteLine("Named Tuple JSON:");
Console.WriteLine(namedTupleJSON);

var unnamedTuple = ("Laptop", 999.99);
var unnamedTupleJSON = JsonConvert.SerializeObject(unnamedTuple);

Console.WriteLine("Unnamed Tuple JSON:");
Console.WriteLine(unnamedTupleJSON);

Output:

Named Tuple JSON:
{"Item1":"Laptop","Item2":999.99}

Unnamed Tuple JSON:
{"Item1":"Laptop","Item2":999.99}

Notice that the JSON output is the same for both the named and unnamed tuple. Despite naming the fields in the tuple declaration, the serializer uses the default field names of Item1 and Item2.

Deserializing a Tuple

To deserialize the tuple back from JSON:

using Newtonsoft.Json;

(string product, double price) item = JsonConvert.DeserializeObject<(string, double)>(json);
Console.WriteLine(item.product); // Outputs Laptop

This works because the deserialization maps the Item1 and Item2 fields from JSON into the corresponding tuple fields by position.

Serializing with System.Text.Json

Tuples in C# are essentially a shorthand for ValueTuple<T1, T2>, which uses fields (rather than properties) named Item1 and Item2. By default, System.Text.Json ignores fields, so it does not serialize tuples unless specifically configured.

To serialize a tuple with System.Text.Json, you need to enable the JsonSerializerOptions.IncludeFields setting, which was introduced in .NET 5.

using System.Text.Json;

var namedTuple = (product: "Laptop", price: 999.99);
var namedTupleJSON = JsonSerializer.Serialize(namedTuple, new JsonSerializerOptions()
{
    IncludeFields = true
});

Console.WriteLine("Named Tuple JSON:");
Console.WriteLine(namedTupleJSON);

var unnamedTuple = ("Laptop", 999.99);
var unnamedTupleJSON = JsonSerializer.Serialize(unnamedTuple, new JsonSerializerOptions()
{
    IncludeFields = true
});

Console.WriteLine("Unnamed Tuple JSON:");
Console.WriteLine(unnamedTupleJSON);

Output:

Named Tuple JSON:
{"Item1":"Laptop","Item2":999.99}

Unnamed Tuple JSON:
{"Item1":"Laptop","Item2":999.99}

Deserialization behaves the same way.

  • The JSON must contain fields named Item1 and Item2.
  • You also need to set JsonSerializerOptions.IncludeFields.
  • When deserializing, specify the type like this: Deserialize<(string, string)>.
  • Whether you use a named or unnamed tuple does not affect the process.
using System.Text.Json;

var jsonOptions = new JsonSerializerOptions()
{
    IncludeFields = true
};

(string product, double price) item = JsonSerializer.Deserialize<(string, double)>(json, jsonOptions);
Console.WriteLine(item.product); // Outputs Laptop

When working with tuples in C#, both Newtonsoft and System.Text.Json serialize them using Item1, Item2, etc., instead of the custom names specified in named tuples. To get better control over the JSON property names, consider using classes or dictionaries if naming the fields is crucial.