Skip to content

Tuples interfaces generics#52891

Open
BillWagner wants to merge 12 commits intodotnet:mainfrom
BillWagner:tuples-interfaces-generics
Open

Tuples interfaces generics#52891
BillWagner wants to merge 12 commits intodotnet:mainfrom
BillWagner:tuples-interfaces-generics

Conversation

@BillWagner
Copy link
Copy Markdown
Member

@BillWagner BillWagner commented Apr 7, 2026

Fixes #51994

Replace anonymous-types.md with a dedicated tuples.md focused on tuples and deconstruction. Revise interfaces.md to trim advanced content (default interface members, static abstract members). Revise generics.md to shift from authoring to consuming generics and add collection expressions, dictionary expressions, spread, and co-/contra-variance. Update snippets, toc.yml, and redirects.


Internal previews

Toggle expand/collapse
📄 File 🔗 Preview link
docs/core/diagnostics/diagnosticsource-diagnosticlistener.md DiagnosticSource and DiagnosticListener
docs/csharp/fundamentals/object-oriented/index.md Overview of object oriented techniques in C#
docs/csharp/fundamentals/types/enums.md "C# Enumerations"
docs/csharp/fundamentals/types/generics.md Generic types and methods
docs/csharp/fundamentals/types/interfaces.md docs/csharp/fundamentals/types/interfaces
docs/csharp/fundamentals/types/tuples.md Tuples and deconstruction
docs/csharp/language-reference/builtin-types/value-tuples.md "Tuple types"
docs/csharp/language-reference/keywords/select-clause.md select clause (C# Reference)
docs/csharp/language-reference/operators/new-operator.md new operator - The new operator creates a new instance of a type
docs/csharp/language-reference/operators/with-expression.md docs/csharp/language-reference/operators/with-expression
docs/csharp/language-reference/statements/declarations.md Declaration statements
docs/csharp/linq/get-started/features-that-support-linq.md "Language features that support LINQ"
docs/csharp/linq/standard-query-operators/index.md Standard query operators overview
docs/csharp/linq/standard-query-operators/join-operations.md docs/csharp/linq/standard-query-operators/join-operations
docs/csharp/misc/cs0746.md Compiler Error CS0746
docs/csharp/misc/cs0833.md "Compiler Error CS0833"
docs/csharp/programming-guide/classes-and-structs/access-modifiers.md Access modifiers (C# programming guide)
docs/csharp/programming-guide/classes-and-structs/anonymous-types.md docs/csharp/programming-guide/classes-and-structs/anonymous-types
docs/csharp/programming-guide/classes-and-structs/how-to-return-subsets-of-element-properties-in-a-query.md How to return subsets of element properties in a query (C# Programming Guide)
docs/csharp/programming-guide/classes-and-structs/how-to-use-implicitly-typed-local-variables-and-arrays-in-a-query-expression.md "How to use implicitly typed local variables and arrays in a query expression"
docs/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables.md Implicitly typed local variables (C# Programming Guide)
docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers
docs/csharp/toc.yml Taken from https://github.com/dotnet/roslyn/wiki/Samples-and-Walkthroughs
docs/csharp/whats-new/csharp-version-history.md The history of C#
docs/fsharp/language-reference/anonymous-records.md Anonymous Records
docs/fundamentals/code-analysis/style-rules/ide0037.md Use inferred member names (IDE0037)
docs/fundamentals/code-analysis/style-rules/ide0050.md docs/fundamentals/code-analysis/style-rules/ide0050
docs/standard/base-types/choosing-between-anonymous-and-tuple.md Choosing between anonymous and tuple types
docs/standard/linq/concepts-terminology-functional-transformation.md Concepts and terminology (functional transformation) - LINQ to XML
docs/standard/linq/project-anonymous-type.md How to project an anonymous type (LINQ to XML)

Note

This table shows preview links for the 30 files with the most changes. For preview links for other files in this PR, select OpenPublishing.Build Details within checks.

1. **Create `fundamentals/types/tuples.md`** — New "Tuples and deconstruction" article replacing `anonymous-types.md`
   - Content: tier tip, tuple declaration with named elements, inferred element names (C# 7.1), tuples as return types, tuple deconstruction (tuple-specific parts merged from `deconstruct.md`), discards (brief, link to `discards.md`), tuple comparison `==`/`!=` (C# 7.3), `with` on tuples, brief "prefer tuples over anonymous types" note linking to language reference
   - Does NOT duplicate: full syntax reference (stays in `value-tuples.md`), user-defined `Deconstruct`/extension methods (stays in `deconstruct.md`)
   - Frontmatter: `ms.topic: concept`, `ai-usage: ai-assisted`, no `f1_keywords`/`helpviewer_keywords`
1. **Create `snippets/tuples/` directory** — `tuples.csproj` (net10.0) + `Program.cs` with all snippet regions. Uses Everyday C# features. *parallel with step 1*
1. **Delete `anonymous-types.md`** and **`snippets/anonymous-types/`** — replaced by tuples. *depends on steps 1–2*
1. **Revise `interfaces.md`** — Remove `helpviewer_keywords`, add `ms.topic: concept` + `ai-usage: ai-assisted` + tier tip. Keep: declaring, implementing (implicit/explicit), interface inheritance, internal interfaces. Trim: default interface members → link to advanced; static abstract → brief mention linking out. Update summary bullets.
1. **Update `snippets/interfaces/`** — `.csproj` to net10.0, modernize `interfaces.cs` with latest features. *depends on step 4*
1. **Revise `generics.md`** — Remove `f1_keywords`/`helpviewer_keywords`, add `ms.topic: concept` + `ai-usage: ai-assisted` + tier tip. Reframe around **consuming** generics (`List<T>`, `Dictionary<TKey,TValue>`, `Task<T>`, `Func<T,TResult>`). Add: type inference, basic constraints (`class`/`struct`/`new()`/base type, brief `Enum`/`Delegate`/`unmanaged`), collection expressions (C# 12) with spread `..`, dictionary expressions (C# 14), co-/contra-variance at consumption level (link to `covariance-contravariance/` for depth). Demote `GenericList<T>` authoring example to secondary.
1. **Update `snippets/generics/`** — `.csproj` to net10.0, rewrite `Program.cs` with consuming-focused examples. *depends on step 6*
1. **Update `docs/csharp/toc.yml`** — Change "Tuples and anonymous types" → "Tuples and deconstruction" pointing to `tuples.md`. Remove `# TODO: tuples` comment.
1. **Update `.openpublishing.redirection.csharp.json`** — Modify existing redirect (`programming-guide/.../anonymous-types.md` → `/dotnet/csharp/fundamentals/types/tuples`). Add new redirect (`fundamentals/types/anonymous-types.md` → `/dotnet/csharp/fundamentals/types/tuples`). Sort alphabetically.
1. **Update cross-references** — Fix links to `anonymous-types.md` in `csharp-version-history.md` and `value-tuples.md` to point to `tuples.md` or language reference.
Replace links to the old anonymous types article.
@BillWagner BillWagner marked this pull request as ready for review April 9, 2026 21:37
@BillWagner BillWagner requested review from a team, adegeo, gewarren and tommcdon as code owners April 9, 2026 21:37
Copilot AI review requested due to automatic review settings April 9, 2026 21:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restructures Everyday C# “type system” documentation by introducing a dedicated tuples article, refocusing interfaces and generics articles for fundamentals readers, and updating cross-references, snippets, TOC, and redirects.

Changes:

  • Replaces the former anonymous-types.md fundamentals article with a new tuples.md focused on tuples and deconstruction, and updates redirects/TOC.
  • Revises interfaces.md and generics.md to emphasize common usage patterns, with refreshed snippets.
  • Updates many docs to repoint anonymous-types references, plus related redirects.

Reviewed changes

Copilot reviewed 37 out of 37 changed files in this pull request and generated 30 comments.

Show a summary per file
File Description
docs/standard/linq/project-anonymous-type.md Updates “Anonymous Types” links to the new fundamentals target.
docs/standard/linq/concepts-terminology-functional-transformation.md Updates anonymous-types reference link in terminology.
docs/standard/base-types/choosing-between-anonymous-and-tuple.md Updates references to fundamentals anonymous-types page.
docs/fundamentals/code-analysis/style-rules/ide0050.md Updates anonymous-types links referenced by the analyzer rule.
docs/fundamentals/code-analysis/style-rules/ide0037.md Updates anonymous-types link in analyzer rule overview.
docs/fsharp/language-reference/anonymous-records.md Updates link for C# anonymous types interop section.
docs/csharp/whats-new/csharp-version-history.md Updates “Anonymous types” link in C# 3.0 feature list.
docs/csharp/toc.yml Replaces the “Tuples and anonymous types” TOC entry with “Tuples and deconstruction”.
docs/csharp/programming-guide/classes-and-structs/object-and-collection-initializers.md Updates link target for anonymous types reference.
docs/csharp/programming-guide/classes-and-structs/implicitly-typed-local-variables.md Updates anonymous types links to new fundamentals target.
docs/csharp/programming-guide/classes-and-structs/how-to-use-implicitly-typed-local-variables-and-arrays-in-a-query-expression.md Updates anonymous types reference link.
docs/csharp/programming-guide/classes-and-structs/how-to-return-subsets-of-element-properties-in-a-query.md Updates “Anonymous Types” link in “See also”.
docs/csharp/programming-guide/classes-and-structs/access-modifiers.md Updates “Anonymous types” link in “See also”.
docs/csharp/misc/cs0833.md Updates “Anonymous Types” link in “See also”.
docs/csharp/misc/cs0746.md Updates “Anonymous Types” link in “See also”.
docs/csharp/linq/standard-query-operators/join-operations.md Updates “Anonymous types” link in “See also”.
docs/csharp/linq/standard-query-operators/index.md Updates “Anonymous Types” link in “See also”.
docs/csharp/linq/get-started/features-that-support-linq.md Updates “anonymous type” link in the anonymous types section.
docs/csharp/language-reference/statements/declarations.md Updates anonymous types link in implicitly-typed locals discussion.
docs/csharp/language-reference/operators/with-expression.md Updates anonymous types link in operand description.
docs/csharp/language-reference/operators/new-operator.md Updates anonymous types link in “Instantiation of anonymous types”.
docs/csharp/language-reference/keywords/select-clause.md Updates “Anonymous Types” link in “See also”.
docs/csharp/language-reference/builtin-types/value-tuples.md Removes link to removed anonymous-types fundamentals page.
docs/csharp/fundamentals/types/tuples.md Adds new fundamentals article for tuples and deconstruction.
docs/csharp/fundamentals/types/snippets/tuples/tuples.csproj Retargets tuples snippet project to net10.0.
docs/csharp/fundamentals/types/snippets/tuples/Program.cs Adds new tuples/deconstruction/equality/with/dictionary examples.
docs/csharp/fundamentals/types/snippets/interfaces/interfaces.csproj Retargets interfaces snippet project to net10.0.
docs/csharp/fundamentals/types/snippets/interfaces/interfaces.cs Reworks interface examples (implicit/explicit impl, inheritance, internal interfaces).
docs/csharp/fundamentals/types/interfaces.md Rewrites the interfaces fundamentals article and references new snippets.
docs/csharp/fundamentals/types/snippets/generics/Program.cs Reworks generics samples toward “consuming generics” and newer syntax examples.
docs/csharp/fundamentals/types/snippets/generics/generics.csproj Retargets generics snippet project to net10.0 and removes explicit startup object.
docs/csharp/fundamentals/types/snippets/anonymous-types/Program.cs Removes old anonymous-types snippet program (file deleted).
docs/csharp/fundamentals/types/generics.md Rewrites generics fundamentals article and references new snippets.
docs/csharp/fundamentals/types/anonymous-types.md Removes old fundamentals anonymous types article (file deleted).
docs/csharp/fundamentals/object-oriented/index.md Updates anonymous types section to point to tuples article.
docs/core/diagnostics/diagnosticsource-diagnosticlistener.md Updates anonymous-type link in DiagnosticSource payload guidance.
.openpublishing.redirection.csharp.json Adds/updates redirects from removed anonymous-types pages to the new tuples page.
Comments suppressed due to low confidence (1)

docs/csharp/misc/cs0833.md:42

  • The “Anonymous Types” reference now links to fundamentals/types/tuples.md, but this compiler error is specifically about anonymous types. Link to anonymous-type documentation (or add an anchor/section in the destination) so the reference matches the error topic.
## See also

- [Anonymous Types](../fundamentals/types/tuples.md)

BillWagner and others added 5 commits April 10, 2026 10:24
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Recreate the anonymous types article in the programming guide section.
Update links to the new anonymous types article, or both the tuples and anonymous types article.
@BillWagner
Copy link
Copy Markdown
Member Author

@adegeo This is ready for final review.


:::code language="csharp" source="snippets/generics/Program.cs" ID="GenericCollections":::

Generic collections prevent type errors at compile time rather than at runtime. They also avoid boxing for value types, which improves performance.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't read quite right as is.

Suggested change
Generic collections prevent type errors at compile time rather than at runtime. They also avoid boxing for value types, which improves performance.
Generic collections prevent type errors at runtime because the errors surface at compile time instead. These collections also avoid boxing for value types, which improves performance.

:::code language="csharp" source="./snippets/interfaces/interfaces.cs" ID="ImplementEquatable":::

Any class or struct that implements the <xref:System.IEquatable`1> interface must contain a definition for an <xref:System.IEquatable`1.Equals*> method that matches the signature that the interface specifies. As a result, you can count on a class of type `T` that implements `IEquatable<T>` to contain an `Equals` method with which an instance of this class can determine whether it's equal to another instance of the same class.
Any class or struct that implements <xref:System.IEquatable`1> must provide an `Equals` method matching the interface signature. You can count on any `IEquatable<T>` implementation to support equality comparison, regardless of the concrete type. That predictability is the core value of interfaces.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Any class or struct that implements <xref:System.IEquatable`1> must provide an `Equals` method matching the interface signature. You can count on any `IEquatable<T>` implementation to support equality comparison, regardless of the concrete type. That predictability is the core value of interfaces.
Any class or struct that implements <xref:System.IEquatable`1> must provide an `Equals` method that matches the interface signature. You can count on any `IEquatable<T>` implementation to support equality comparison, regardless of the concrete type. That predictability is the core value of interfaces.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-ing words are more amiguous


## Interface inheritance

Interfaces can inherit from one or more other interfaces. A class implementing a derived interface must implement all members from the derived interface and all of its base interfaces:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Interfaces can inherit from one or more other interfaces. A class implementing a derived interface must implement all members from the derived interface and all of its base interfaces:
Interfaces can inherit from one or more other interfaces. A class that implements a derived interface must implement all members from the derived interface and all of its base interfaces:

- **Default interface members** let an interface provide a method body. Implementing types inherit the default implementation and can optionally override it. For more information, see [default interface methods](../../advanced-topics/interface-implementation/default-interface-methods-versions.md).
- **Static abstract members** require implementing types to provide a static member, which is useful for defining operator contracts or factory patterns. For more information, see [static abstract members in interfaces](../../language-reference/keywords/interface.md#static-abstract-and-virtual-members).

Both features are covered in the advanced topics section. Most everyday interface usage involves the declaring and implementing patterns described earlier in this article.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does the "advanced topics" section refer to, a section in the TOC?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to check this in?


## When to use tuples instead

For most new code, consider using [tuples](../../fundamentals/types/tuples.md#tuples-vs-anonymous-types) instead of anonymous types. Tuples provide better performance as value types, deconstruction support, and more flexible syntax. Anonymous types remain the better choice when you need expression tree support or reference-type semantics. For a detailed comparison, see [Choosing between anonymous and tuple types](../../../standard/base-types/choosing-between-anonymous-and-tuple.md).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
For most new code, consider using [tuples](../../fundamentals/types/tuples.md#tuples-vs-anonymous-types) instead of anonymous types. Tuples provide better performance as value types, deconstruction support, and more flexible syntax. Anonymous types remain the better choice when you need expression tree support or reference-type semantics. For a detailed comparison, see [Choosing between anonymous and tuple types](../../../standard/base-types/choosing-between-anonymous-and-tuple.md).
For most new code, consider using [tuples](../../fundamentals/types/tuples.md#tuples-vs-anonymous-types) instead of anonymous types. As value types, tuples provide better performance. They also provide deconstruction support and more flexible syntax. Anonymous types remain the better choice when you need expression tree support or reference-type semantics. For a detailed comparison, see [Choosing between anonymous and tuple types](../../../standard/base-types/choosing-between-anonymous-and-tuple.md).

:::code language="csharp" source="snippets/with-expression/BasicExample.cs" :::

The left-hand operand of a `with` expression can be a [record type](../builtin-types/record.md). It can also be a [structure type](../builtin-types/struct.md) or an [anonymous type](../../fundamentals/types/anonymous-types.md).
The left-hand operand of a `with` expression can be a [record type](../builtin-types/record.md). It can also be a [structure type](../builtin-types/struct.md), [tuple](../builtin-types/value-tuples.md), or an [anonymous type](../../programming-guide/classes-and-structs/anonymous-types.md).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The left-hand operand of a `with` expression can be a [record type](../builtin-types/record.md). It can also be a [structure type](../builtin-types/struct.md), [tuple](../builtin-types/value-tuples.md), or an [anonymous type](../../programming-guide/classes-and-structs/anonymous-types.md).
The left-hand operand of a `with` expression can be a [record type](../builtin-types/record.md). It can also be a [structure type](../builtin-types/struct.md), a [tuple](../builtin-types/value-tuples.md), or an [anonymous type](../../programming-guide/classes-and-structs/anonymous-types.md).

"redirections": [
{
"source_path_from_root": "/docs/csharp/fundamentals/types/anonymous-types.md",
"redirect_url": "/dotnet/csharp/fundamentals/types/tuples"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this redirect to the new anonymous-types.md article instead and redirect document ID?

>
> **Experienced in another language?** C# tuples are value types similar to tuples in Python or Swift, but with optional named elements and full deconstruction support. Skim the [deconstruction](#deconstruct-tuples) and [equality](#tuple-equality) sections for C#-specific patterns.

A *tuple* groups multiple values into a single, lightweight structure without requiring you to define a named type. Tuples are value types that you can declare inline, return from methods, and deconstruct into individual variables. Use tuples when you need a quick, temporary grouping of related values. For example, returning multiple results from a method or storing a coordinate pair.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A *tuple* groups multiple values into a single, lightweight structure without requiring you to define a named type. Tuples are value types that you can declare inline, return from methods, and deconstruct into individual variables. Use tuples when you need a quick, temporary grouping of related values. For example, returning multiple results from a method or storing a coordinate pair.
A *tuple* groups multiple values into a single, lightweight structure without requiring you to define a named type. Tuples are value types that you can declare inline, return from methods, and deconstruct into individual variables. Use tuples when you need a quick, temporary grouping of related values. For example, when you return multiple results from a method or store a coordinate pair.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 9's grammar isn't quite correct. Suggestion:

Since then, new options have been introduced with language -level support, such as xref:System.ValueTuple`2?displayProperty=nameWithType. As the names imply, these options provide a value type with the flexibility of anonymous types.

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.

[Everyday C#] Phase B, Task 5: Type system: tuples, enums, intefaces

4 participants