You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/builtin-types/record.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
title: "Records"
3
3
description: Learn about the record modifier for class and struct types in C#. Records provide standard support for value based equality on instances of record types.
4
-
ms.date: 01/14/2026
4
+
ms.date: 06/05/2026
5
5
f1_keywords:
6
6
- "record_CSharpKeyword"
7
7
helpviewer_keywords:
@@ -228,14 +228,14 @@ The result of a `with` expression has the same run-time type as the expression's
228
228
229
229
### `PrintMembers` formatting in derived records
230
230
231
-
The synthesized `PrintMembers` method of a derived record type calls the base implementation. The result is that all public properties and fields of both derived and base types are included in the `ToString` output, as shown in the following example:
231
+
The synthesized `PrintMembers` method of a derived record type calls the base implementation. The result is that the `ToString` output includes all public properties and fields of both derived and base types, as shown in the following example:
You can provide your own implementation of the `PrintMembers` method. If you do that, use the following signature:
235
+
You can provide your own implementation of the `PrintMembers` method. If you do, use the following signature:
236
236
237
237
* For a `sealed` record that derives from `object` (doesn't declare a base record): `private bool PrintMembers(StringBuilder builder)`;
238
-
* For a `sealed` record that derives from another record (note that the enclosing type is `sealed`, so the method is effectively `sealed`): `protected override bool PrintMembers(StringBuilder builder)`;
238
+
* For a `sealed` record that derives from another record (the enclosing type is `sealed`, so the method is effectively `sealed`): `protected override bool PrintMembers(StringBuilder builder)`;
239
239
* For a record that isn't `sealed` and derives from object: `protected virtual bool PrintMembers(StringBuilder builder);`
240
240
* For a record that isn't `sealed` and derives from another record: `protected override bool PrintMembers(StringBuilder builder);`
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/keywords/closed.md
+14-9Lines changed: 14 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,9 +13,7 @@ ai-usage: ai-assisted
13
13
---
14
14
# closed (C# Reference)
15
15
16
-
Starting in C# 15, you can apply the `closed` modifier to a class to declare a *closed hierarchy*. A closed class can only be derived from within its declaring assembly. Because the set of direct descendants is fixed, a `switch` expression that handles each direct descendant exhausts the closed base type and doesn't need a default arm.
Starting in C# 15, you can apply the `closed` modifier to a class to declare a *closed hierarchy*. You can only derive a direct subtype from a closed class within its declaring assembly. Because the set of direct descendants is fixed, a `switch` expression that handles each direct descendant exhausts the closed base type and doesn't need a default arm.
19
17
20
18
```csharp
21
19
// Assembly 1
@@ -38,17 +36,28 @@ public record class RetryableFailed(string Error, int Attempts) : Failed(Error);
38
36
39
37
If you want to prevent derivation from `Failed` as well, declare it as `sealed` or `closed`.
>`closed` is a contextual keyword. It has special meaning only when it appears as a modifier on a class declaration. You can continue to use `closed` as an identifier in other contexts. If you need to use `closed` as an identifier in a position where the modifier would also be valid, prefix it with `@` (for example, `@closed`) to tell the compiler to treat it as an identifier rather than the modifier.
43
+
41
44
## Declaration rules
42
45
43
46
The `closed` modifier is a class modifier:
44
47
45
48
- A `closed` class is implicitly [`abstract`](abstract.md). You can't combine `closed` with `sealed`, `static`, or an explicit `abstract` modifier.
46
-
-A direct subtype of a closed class must be declared in the same assembly and module as the closed base class.
49
+
-You must declare a direct subtype of a closed class in the same assembly and module as the closed base class.
47
50
- A class that derives from a closed class isn't itself closed. Apply the `closed` modifier again if you want a derived class to also be closed.
48
51
49
52
If a generic class directly derives from a `closed` class, every type parameter on the derived class must be used in the base class specification. This rule isn't about the `closed` modifier itself: a *closed constructed type* is a generic type whose type arguments are fully specified (such as `Tree<int>`), as opposed to an *open type* like `Tree<T>`. The rule ensures that each closed constructed type of the base class has exactly one corresponding closed constructed type among its direct descendants, so the compiler can reason about exhaustiveness.
publicrecordclassLeaf<T>(TValue) : Tree<T>; // OK: 'T' appears in the base class
58
+
publicrecordclassBranch<T>(Tree<T> Left, Tree<T> Right) : Tree<T>; // OK: 'T' appears in the base class
59
+
publicrecordclassConstant<U>(UValue) : Tree<int> { } // Error: 'U' isn't used in the base class
60
+
```
52
61
53
62
## Exhaustive switch expressions
54
63
@@ -72,10 +81,6 @@ A type parameter constrained to a closed class is treated as that closed class f
72
81
73
82
This rule applies whether the type parameter appears on a method or on the containing type.
74
83
75
-
## Contextual keyword
76
-
77
-
`closed` is a contextual keyword. It has special meaning only when it appears as a modifier on a class declaration. You can continue to use `closed` as an identifier in other contexts. If you need to use `closed` as an identifier in a position where the modifier would also be valid, prefix it with `@` (for example, `@closed`) to tell the compiler to treat it as an identifier rather than the modifier.
78
-
79
84
## C# language specification
80
85
81
86
For more information, see the [Closed hierarchies](~/_csharplang/proposals/closed-hierarchies.md) feature specification.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/operators/patterns.md
+11-3Lines changed: 11 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
title: "Patterns - Pattern matching using the is and switch expressions."
3
3
description: "Learn about the patterns supported by the `is` and `switch` expressions. Combine multiple patterns using the `and`, `or`, and `not` operators."
4
-
ms.date: 03/20/2026
4
+
ms.date: 06/05/2026
5
5
f1_keywords:
6
6
- "and_CSharpKeyword"
7
7
- "or_CSharpKeyword"
@@ -318,7 +318,7 @@ For example, a closed `public` base class can have an `internal` direct descenda
To restore exhaustiveness in assembly 2, add a discard arm (`_ => ...`) or make every direct descendant at least as accessible as the closed base type.
321
+
To restore exhaustiveness in assembly 2, add a discard arm (`_ => ...`), add a base class arm (`Shape` in the preceding example), or make every direct descendant at least as accessible as the closed base type.
322
322
323
323
When the governing type is nullable, `null` is an additional value the switch must handle. A switch over `PaymentMethod?` that omits a `null` arm isn't exhaustive even when every direct descendant is matched.
324
324
@@ -347,7 +347,15 @@ string Category(Vehicle v) => v switch
0 commit comments