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
* Fixes#27149
This first commit fixes#27149
In addition to the notes on that issues, emphasize the difference in the behavior of the synthesized parameterless constructor based on the presence of field initializers and other instance constructors.
* Fixes#27154
Fix the description of positional parameters where you declare the property declaration in your source.
* Fixes#27157
Reword sentence on `with` expressions and assignment.
* Fixes#27158
Correctly point out that the string for each property is obtained by calling `ToString` on that property type.
* Fixes#27171
Clarify that the property is `sealed` because the enclosing type is `sealed`. (The property declaration need not include the `sealed` modifier)
* Fixes#27173
The method signature doesn't need the `sealed` modifier because the type is sealed.
* Fixes#27174
Add motivation for sealing ToString in records.
* update dates.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/builtin-types/record.md
+12-12Lines changed: 12 additions & 12 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 - C# reference"
3
3
description: Learn about the record type in C#
4
-
ms.date: 09/30/2021
4
+
ms.date: 12/16/2021
5
5
f1_keywords:
6
6
- "record_CSharpKeyword"
7
7
helpviewer_keywords:
@@ -53,20 +53,20 @@ You can use positional parameters to declare properties of a record and to initi
53
53
54
54
When you use the positional syntax for property definition, the compiler creates:
55
55
56
-
* A public init-only auto-implemented property for each positional parameter provided in the record declaration.
57
-
- For `record` types and `readonly record struct` types: An [init-only](../keywords/init.md) property can only be set in the constructor or by using a property initializer.
58
-
- For `record struct` types: A read-write property that can be set in a constructor, property initializer, or assignment after construction.
56
+
* A public auto-implemented property for each positional parameter provided in the record declaration.
57
+
- For `record` types and `readonly record struct` types: An [init-only](../keywords/init.md) property.
58
+
- For `record struct` types: A read-write property.
59
59
* A primary constructor whose parameters match the positional parameters on the record declaration.
60
60
* For record struct types, a parameterless constructor that sets each field to its default value.
61
-
* A `Deconstruct` method with an `out` parameter for each positional parameter provided in the record declaration. This method is provided only if there are two or more positional parameters. The method deconstructs properties defined by using positional syntax; it ignores properties that are defined by using standard property syntax.
61
+
* A `Deconstruct` method with an `out` parameter for each positional parameter provided in the record declaration. The method deconstructs properties defined by using positional syntax; it ignores properties that are defined by using standard property syntax.
62
62
63
63
You may want to add attributes to any of these elements the compiler creates from the record definition. You can add a *target* to any attribute you apply to the positional record's properties. The following example applies the <xref:System.Text.Json.Serialization.JsonPropertyNameAttribute?displayProperty=nameWithType> to each property of the `Person` record. The `property:` target indicates that the attribute is applied to the compiler-generated property. Other values are `field:` to apply the attribute to the field, and `param:` to apply the attribute to the parameter.
The preceding example also shows how to create XML documentation comments for the record. You can add the `<param>` tag to add documentation for the primary constructor's parameters.
68
68
69
-
If the generated auto-implemented property definition isn't what you want, you can define your own property of the same name. If you do that, the generated constructor and deconstructor will use your property definition. For instance, the following example declares the `FirstName` and `LastName` properties of a positional record `public`, but restricts the `Id` positional parameter to `internal`. You can use this syntax for records and record struct types. You must add the explicit assignment of the declared property to its corresponding positional parameter.
69
+
If the generated auto-implemented property definition isn't what you want, you can define your own property of the same name. For example, you may want to change accessibility or mutability, or provide an implementation for either the `get` or `set` accessor. If you declare the property in your source, you must initialize it from the positional parameter of the record. The generated deconstructor will use your property definition. For instance, the following example declares the `FirstName` and `LastName` properties of a positional record `public`, but restricts the `Id` positional parameter to `internal`. You can use this syntax for records and record struct types.
@@ -133,7 +133,7 @@ The result of a `with` expression is a *shallow copy*, which means that for a re
133
133
134
134
To implement this feature for `record class` types, the compiler synthesizes a clone method and a copy constructor. The virtual clone method returns a new record initialized by the copy constructor. When you use a `with` expression, the compiler creates code that calls the clone method and then sets the properties that are specified in the `with` expression.
135
135
136
-
If you need different copying behavior, you can write your own copy constructor in a `record class`. If you do that, the compiler won't synthesize one. Make your constructor `private` if the record is `sealed`, otherwise make it `protected`. The compiler doesn't synthesize a copy constructor for `record struct` types. You can write one, but the compiler won't generate calls to it for `with` expressions. Instead, the compiler uses assignment.
136
+
If you need different copying behavior, you can write your own copy constructor in a `record class`. If you do that, the compiler won't synthesize one. Make your constructor `private` if the record is `sealed`, otherwise make it `protected`. The compiler doesn't synthesize a copy constructor for `record struct` types. You can write one, but the compiler won't generate calls to it for `with` expressions. The values of the `record struct` are copied on assignment.
137
137
138
138
You can't override the clone method, and you can't create a member named `Clone` in any record type. The actual name of the clone method is compiler-generated.
139
139
@@ -143,7 +143,7 @@ Record types have a compiler-generated <xref:System.Object.ToString%2A> method t
For reference types, the type name of the object that the property refers to is displayed instead of the property value. In the following example, the array is a reference type, so `System.String[]` is displayed instead of the actual array element values:
146
+
The string printed for `<value>` is the string returned by the <xref:System.Object.ToString> for the type of the property. In the following example, `ChildNames`is a <xref:System.Array?displayProperty=nameWithType>, where `ToString` returns `System.String[]`:
You can provide your own implementation of `PrintMembers` or the `ToString` override. Examples are provided in the [`PrintMembers` formatting in derived records](#printmembers-formatting-in-derived-records) section later in this article. In C# 10 and later, your implementation of `ToString` may include the `sealed` modifier, which prevents the compiler from synthesizing a `ToString` implementation for any derived records. Effectively, that means the `ToString` output won't include the runtime type information. (All members and values are displayed, because derived records will still have a PrintMembers method generated.)
157
+
You can provide your own implementation of `PrintMembers` or the `ToString` override. Examples are provided in the [`PrintMembers` formatting in derived records](#printmembers-formatting-in-derived-records) section later in this article. In C# 10 and later, your implementation of `ToString` may include the `sealed` modifier, which prevents the compiler from synthesizing a `ToString` implementation for any derived records. You can do this to create a consistent string representation throughout a hierarchy of `record` types. (Derived records will still have a `PrintMembers` method generated for all derived properties.)
158
158
159
159
## Inheritance
160
160
@@ -178,7 +178,7 @@ This section applies to `record class` types, but not `record struct` types. For
178
178
179
179
In the example, all variables are declared as `Person`, even when the instance is a derived type of either `Student` or `Teacher`. The instances have the same properties and the same property values. But `student == teacher` returns `False` although both are `Person`-type variables, and `student == student2` returns `True` although one is a `Person` variable and one is a `Student` variable. The equality test depends on the runtime type of the actual object, not the declared type of the variable.
180
180
181
-
To implement this behavior, the compiler synthesizes an `EqualityContract` property that returns a <xref:System.Type> object that matches the type of the record. The `EqualityContract` enables the equality methods to compare the runtime type of objects when they're checking for equality. If the base type of a record is `object`, this property is `virtual`. If the base type is another record type, this property is an override. If the record type is `sealed`, this property is `sealed`.
181
+
To implement this behavior, the compiler synthesizes an `EqualityContract` property that returns a <xref:System.Type> object that matches the type of the record. The `EqualityContract` enables the equality methods to compare the runtime type of objects when they're checking for equality. If the base type of a record is `object`, this property is `virtual`. If the base type is another record type, this property is an override. If the record type is `sealed`, this property is effectively `sealed` because the type is `sealed`.
182
182
183
183
When comparing two instances of a derived type, the synthesized equality methods check all properties of the base and derived types for equality. The synthesized `GetHashCode` method uses the `GetHashCode` method from all properties and fields declared in the base type and the derived record type.
184
184
@@ -197,7 +197,7 @@ The synthesized `PrintMembers` method of a derived record type calls the base im
197
197
You can provide your own implementation of the `PrintMembers` method. If you do that, use the following signature:
198
198
199
199
* For a `sealed` record that derives from `object` (doesn't declare a base record): `private bool PrintMembers(StringBuilder builder)`;
200
-
* For a `sealed` record that derives from another record: `protected sealed override bool PrintMembers(StringBuilder builder)`;
200
+
* 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)`;
201
201
* For a record that isn't `sealed` and derives from object: `protected virtual bool PrintMembers(StringBuilder builder);`
202
202
* For a record that isn't `sealed` and derives from another record: `protected override bool PrintMembers(StringBuilder builder);`
203
203
@@ -206,7 +206,7 @@ Here's an example of code that replaces the synthesized `PrintMembers` methods,
> In C# 10 and later, the compiler will synthesize `PrintMembers` when a base record has sealed the `ToString` method. You can also create your own implementation of `PrintMembers`.
209
+
> In C# 10 and later, the compiler will synthesize `PrintMembers`in derived records even when a base record has sealed the `ToString` method. You can also create your own implementation of `PrintMembers`.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/builtin-types/struct.md
+4-1Lines changed: 4 additions & 1 deletion
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: "Structure types - C# reference"
3
3
description: Learn about the struct type in C#
4
-
ms.date: 09/15/2021
4
+
ms.date: 12/16/2021
5
5
f1_keywords:
6
6
- "struct_CSharpKeyword"
7
7
helpviewer_keywords:
@@ -118,6 +118,9 @@ If you don't declare a parameterless constructor explicitly, a structure type pr
118
118
119
119
As the preceding example shows, the default value expression and array instantiation ignore field initializers.
120
120
121
+
> [!IMPORTANT]
122
+
> When a `struct` includes field initializers, but doesn't include any explicit instance constructors, the synthesized public parameterless constructor performs the specified field initializers. If that `struct` includes an explicit instance constructor, the synthesized parameterless constructor produces the same value as the `default` expression.
123
+
121
124
For more information, see the [Parameterless struct constructors](~/_csharplang/proposals/csharp-10.0/parameterless-struct-constructors.md) feature proposal note.
0 commit comments