Skip to content

Add serialization support for tuple types#126054

Draft
eiriktsarpalis wants to merge 2 commits intodotnet:mainfrom
eiriktsarpalis:prototype/tuples
Draft

Add serialization support for tuple types#126054
eiriktsarpalis wants to merge 2 commits intodotnet:mainfrom
eiriktsarpalis:prototype/tuples

Conversation

@eiriktsarpalis
Copy link
Copy Markdown
Member

Note

This PR was AI/Copilot-generated.

Summary

Adds first-class serialization support for ValueTuple and System.Tuple types in System.Text.Json. Tuples now serialize without requiring IncludeFields = true.

Key feature: Tuple element flattening

For tuples with more than 7 elements, the internal Rest nesting structure is flattened so that elements appear with logical names (Item1 through ItemN) at the top level:

var tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
JsonSerializer.Serialize(tuple);
// {"Item1":1,"Item2":2,...,"Item7":7,"Item8":8,"Item9":9,"Item10":10}

This works for both ValueTuple (struct tuples) and System.Tuple (class tuples), and for both the reflection-based and source-generated serializers.

Implementation

Source generator:

  • Parser walks tuple elements across the Rest chain and emits flattened property specs with Rest.Rest...ItemN accessor patterns
  • Emitter generates nested constructor chains for deserialization
  • IsTupleElement flag on PropertyGenerationSpec bypasses IncludeFields check in fast path

Reflection path:

  • FlattenTupleProperties post-processes the property list to replace Rest with synthesized Item8+ properties
  • MemberAccessor.CreateTupleElementGetter/Setter provides IL-emitted accessors for nested field chains
  • ReflectionMemberAccessor provides a reflection-based fallback for AOT scenarios
  • Nested constructor delegates handle deserialization of >7-element tuples

No new public API surface. Tuple detection and field inclusion are handled internally.

Fixes #70352

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@hez2010
Copy link
Copy Markdown
Contributor

hez2010 commented Mar 25, 2026

Put my two cents here:

Tuples should be serialized into array, because that's how tuples works in JavaScript:

const [first, second, third, ...] = tuple;

@eiriktsarpalis eiriktsarpalis marked this pull request as draft March 25, 2026 07:13
@eiriktsarpalis
Copy link
Copy Markdown
Member Author

Put my two cents here:

Tuples should be serialized into array, because that's how tuples works in JavaScript:

const [first, second, third, ...] = tuple;

It's in the cards, but that would necessarily have to be an opt in feature (aka necessitating new API to opt us into it).

@stephentoub
Copy link
Copy Markdown
Member

that would necessarily have to be an opt in feature

Why?

@eiriktsarpalis
Copy link
Copy Markdown
Member Author

that would necessarily have to be an opt in feature

Why?

Tuples serialize as objects today (albeit with issues). I think there is merit in keeping this as the default behaviour

@hez2010
Copy link
Copy Markdown
Contributor

hez2010 commented Mar 27, 2026

I think there is merit in keeping this as the default behaviour

The existing behavior is already incorrect:

  • it requires IncludeFields to properly serialize tuples
  • it doesn't flatten the tuple, instead it produces nested object in Rest

Flattening it will be a breaking change, too.

So in either way this will be a breaking change. I think the right move should be making breaking change toward correcting the behavior to match JavaScript given that the breaking change here is unavoidable.

@eiriktsarpalis
Copy link
Copy Markdown
Member Author

So in either way this will be a breaking change

It would not break people serializing tuples of arity < 8 (which represents 95% of tuple use cases) that have enabled IncludeFields. For every other case, deserialization would still succeed on account of the schema type remaining the same.

I think the right move should be making breaking change toward correcting the behavior to match JavaScript given that the breaking change here is unavoidable.

If you're talking about TypeScript tuple types, these represent a refinement over js arrays. Their serialization as JSON arrays is therefore a natural consequence of their run-time representation. While I don't disagree that we should try to support this mode, I don't see it as a natural or better way of representing tuples.

…x trimming

- Replace string-based IsReferenceTupleType in source generator parser with
  symbol comparison via KnownTypeSymbols (addresses @stephentoub feedback)
- Move IsTupleType from DefaultJsonTypeInfoResolver to JsonHelpers to avoid
  rooting DefaultJsonTypeInfoResolver from the source-gen metadata path,
  which prevented it from being trimmed when IsReflectionEnabledByDefault=false

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JsonSerializer should serialize tuples by default

3 participants