.Net JsonSerializer does not serialize tuple's values
Asked Answered
P

2

16

JSON serializer returns an empty JSON object.

using System.Text.Json;

(int, int) tuple1 = (1, 2);
var token = JsonSerializer.Serialize(tuple1); // return empty object {}

(int item1, int item2) tuple2 = (1, 2);
token = JsonSerializer.Serialize(tuple2); // return empty object {}

(int item1, int item2) tuple3 = (item1:1, item2:2);
token = JsonSerializer.Serialize(tuple3); // return empty object {}

it can be passed by many workarounds

I'm trying to understand why or what prevents the serializer to understands the tuples

is it related to the tuples' structure

Pastel answered 21/12, 2021 at 14:2 Comment(6)
Why are you using tuples? What would you expect to get? A ValueTuple has no properties, only public fields. Those fields are named Item1, Item2 etc.President
github.com/dotnet/runtime/issues/31004Hamner
I find it interesting that the serializer works with a more explicit Tuple<int,int> with the properties Item1 and Item2Bregenz
@TJRockefeller those are classes and they actually have properties. value tuples do not.Hamner
@TJRockefeller it's not more explicit, it's completely different. A Tuple<int,int> is a referencey type with properties. (int,int) is a ValueTuple, a struct with fields. Serializers work with properties by default because fields are typically implementation detailsPresident
@PanagiotisKanavos that is very good to know, this whole time I thought that value tuples were just syntax sugar and basically aliases of TupleBregenz
P
24

A ValueTuple doesn't have properties, only public fields. Until .NET 6, System.Text.Json only serialized public properties. This is the most common case, as fields are considered implementation, not part of an object's API. All serializers prioritize properties over fields unless instructed to also serialize fields.

.NET 6 added the ability to serialize fields in a similar way to other serializer, either with an attribute over a field or a serializer setting.

Since we can't add attributes to a tuple field, we can use settings:

var options = new JsonSerializerOptions
{
    IncludeFields = true,
};
var json = JsonSerializer.Serialize(tuple1, options);

This produces :

 {"Item1":1,"Item2":2}
President answered 21/12, 2021 at 14:13 Comment(5)
what about preserving field's name for valuetuples?Broadsword
@Broadsword if you want that, use records. In ValueTuples the "field" names are just labels and compiler magic. The actual fields are still Field1, Field2 etc. The labels aren't preserved after compilationPresident
Nothing new, I know all those sad facts. Just supposed there some changes wereBroadsword
Why use value tuples when you have struct records for this job? Value tuples were never meant to be part of a component's public API, which is what gets serialized.President
Quite simply reason - I don't like to strictly define classes/structures/records just for one response. ValeuTuples fit the case perfectlyBroadsword
B
4

Just incase someone cares about deserialization, and you have a more complex class with Tuples.

public class Foo
{
    public (string key, string value) Tuple1{ get; set; }
}

var options = new JsonSerializerOptions
{
    IncludeFields = true,
};

string jsonString = File.ReadAllText("myconfig.json");
Foo obj1 = JsonSerializer.Deserialize<Foo>(jsonString, options);
Buddhism answered 20/4, 2022 at 23:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.