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
Clarify that positional parameters can create fields (#44691)
* Clarify that positional parameters can create fields
Record types with positional parameters can synthesize fields as well as parameters. Make that more clear.
* fix warnings
* Update docs/csharp/language-reference/builtin-types/record.md
Co-authored-by: Genevieve Warren <[email protected]>
* respond to feedback
---------
Co-authored-by: Genevieve Warren <[email protected]>
Copy file name to clipboardExpand all lines: docs/csharp/fundamentals/coding-style/identifier-names.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -123,7 +123,7 @@ public record PhysicalAddress(
123
123
stringZipCode);
124
124
```
125
125
126
-
For more information on positional records, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-definition).
126
+
For more information on positional records, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition).
Copy file name to clipboardExpand all lines: docs/csharp/fundamentals/functional/deconstruct.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -102,7 +102,7 @@ Some system types provide the `Deconstruct` method as a convenience. For example
102
102
103
103
## `record` types
104
104
105
-
When you declare a [record](../../language-reference/builtin-types/record.md) type by using two or more positional parameters, the compiler creates a `Deconstruct` method with an `out` parameter for each positional parameter in the `record` declaration. For more information, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-definition) and [Deconstructor behavior in derived records](../../language-reference/builtin-types/record.md#deconstructor-behavior-in-derived-records).
105
+
When you declare a [record](../../language-reference/builtin-types/record.md) type by using two or more positional parameters, the compiler creates a `Deconstruct` method with an `out` parameter for each positional parameter in the `record` declaration. For more information, see [Positional syntax for property definition](../../language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition) and [Deconstructor behavior in derived records](../../language-reference/builtin-types/record.md#deconstructor-behavior-in-derived-records).
Copy file name to clipboardExpand all lines: docs/csharp/fundamentals/types/records.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -33,7 +33,7 @@ Immutability isn't appropriate for all data scenarios. [Entity Framework Core](/
33
33
34
34
The same syntax that [declares](classes.md#declaring-classes) and [instantiates](classes.md#creating-objects) classes or structs can be used with records. Just substitute the `class` keyword with the `record`, or use `record struct` instead of `struct`. Likewise, the same syntax for expressing inheritance relationships is supported by record classes. Records differ from classes in the following ways:
35
35
36
-
* You can use [positional parameters](../../language-reference/builtin-types/record.md#positional-syntax-for-property-definition) in a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) to create and instantiate a type with immutable properties.
36
+
* You can use [positional parameters](../../language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition) in a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) to create and instantiate a type with immutable properties.
37
37
* The same methods and operators that indicate reference equality or inequality in classes (such as <xref:System.Object.Equals(System.Object)?displayProperty=nameWithType> and `==`), indicate [value equality or inequality](../../language-reference/builtin-types/record.md#value-equality) in records.
38
38
* You can use a [`with` expression](../../language-reference/builtin-types/record.md#nondestructive-mutation) to create a copy of an immutable object with new values in selected properties.
39
39
* A record's `ToString` method creates a formatted string that shows an object's type name and the names and values of all its public properties.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/attributes/general.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -129,7 +129,7 @@ If <xref:System.AttributeUsageAttribute.Inherited> is `false`, then derived clas
129
129
130
130
In this case, `NonInheritedAttribute` isn't applied to `DClass` via inheritance.
131
131
132
-
You can also use these keywords to specify where an attribute should be applied. For example, you can use the `field:` specifier to add an attribute to the backing field of an [automatically implemented property](../../programming-guide/classes-and-structs/properties.md#automatically-implemented-properties). Or you can use the `field:`, `property:` or `param:` specifier to apply an attribute to any of the elements generated from a positional record. For an example, see [Positional syntax for property definition](../builtin-types/record.md#positional-syntax-for-property-definition).
132
+
You can also use these keywords to specify where an attribute should be applied. For example, you can use the `field:` specifier to add an attribute to the backing field of an [automatically implemented property](../../programming-guide/classes-and-structs/properties.md#automatically-implemented-properties). Or you can use the `field:`, `property:` or `param:` specifier to apply an attribute to any of the elements generated from a positional record. For an example, see [Positional syntax for property definition](../builtin-types/record.md#positional-syntax-for-property-and-field-definition).
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/builtin-types/record.md
+13-9
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
---
2
2
title: "Records"
3
-
description: Learn about the record type in C#
4
-
ms.date: 11/22/2023
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: 02/05/2025
5
5
f1_keywords:
6
6
- "record_CSharpKeyword"
7
7
helpviewer_keywords:
@@ -35,7 +35,7 @@ Record structs can be mutable as well, both positional record structs and record
35
35
36
36
While records can be mutable, they're primarily intended for supporting immutable data models. The record type offers the following features:
37
37
38
-
*[Concise syntax for creating a reference type with immutable properties](#positional-syntax-for-property-definition)
38
+
*[Concise syntax for creating a reference type with immutable properties](#positional-syntax-for-property-and-field-definition)
39
39
* Built-in behavior useful for a data-centric reference type:
40
40
*[Value equality](#value-equality)
41
41
*[Concise syntax for nondestructive mutation](#nondestructive-mutation)
@@ -49,9 +49,9 @@ The preceding examples show some distinctions between records that are reference
49
49
50
50
The remainder of this article discusses both `record class` and `record struct` types. The differences are detailed in each section. You should decide between a `record class` and a `record struct` similar to deciding between a `class` and a `struct`. The term *record* is used to describe behavior that applies to all record types. Either `record struct` or `record class` is used to describe behavior that applies to only struct or class types, respectively.
51
51
52
-
## Positional syntax for property definition
52
+
## Positional syntax for property and field definition
53
53
54
-
You can use positional parameters to declare properties of a record and to initialize the property values when you create an instance:
54
+
You can use positional parameters to declare properties of a record or to initialize property or field values. The following example creates a record with two positional properties:
@@ -70,19 +70,23 @@ You might want to add attributes to any of these elements the compiler creates f
70
70
71
71
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.
72
72
73
-
If the generated automatically implemented property definition isn't what you want, you can define your own property of the same name. For example, you might 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. If your property is an automatically implemented property, you must initialize the property. If you add a backing field in your source, you must initialize the backing field. The generated deconstructor uses 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.
73
+
If the generated automatically implemented property definition isn't what you want, you can define your own property or field of the same name. For example, you might want to change accessibility or mutability, or provide an implementation for either the `get` or `set` accessor. If you declare the member in your source, you must initialize it from the positional parameter of the record. If your property is an automatically implemented property, you must initialize the property. If you add a backing field in your source, you must initialize the backing field. The generated deconstructor uses your property or field 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.
A record type doesn't have to declare any positional properties. You can declare a record without any positional properties, and you can declare other fields and properties, as in the following example:
If you define properties by using standard property syntax but omit the access modifier, the properties are implicitly `private`.
85
+
Properties that the compiler generates from positional parameters are `public`. You declare the access modifiers on any properties you explicitly declare.
82
86
83
87
## Immutability
84
88
85
-
A *positional record* and a *positional readonly record struct* declare init-only properties. A *positional record struct* declares read-write properties. You can override either of those defaults, as shown in the previous section.
89
+
A *positional record class* and a *positional readonly record struct* declare init-only properties. A *positional record struct* declares read-write properties. You can override either of those defaults, as shown in the previous section.
86
90
87
91
Immutability can be useful when you need a data-centric type to be thread-safe or you're depending on a hash code remaining the same in a hash table. Immutability isn't appropriate for all data scenarios, however. [Entity Framework Core](/ef/core/), for example, doesn't support updating with immutable entity types.
88
92
@@ -211,7 +215,7 @@ Here's an example of code that replaces the synthesized `PrintMembers` methods,
> 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`.
218
+
> The compiler synthesizes `PrintMembers` in derived records even when a base record sealed the `ToString` method. You can also create your own implementation of `PrintMembers`.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/keywords/required.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -19,7 +19,7 @@ The `required` modifier indicates that the *field* or *property* it's applied to
19
19
- A type with any `required` members may not be used as a type argument when the type parameter includes the `new()` constraint. The compiler can't enforce that all required members are initialized in the generic code.
20
20
- The `required` modifier isn't allowed on the declaration for positional parameters on a record. You can add an explicit declaration for a positional property that does include the `required` modifier.
21
21
22
-
Some types, such as [positional records](../builtin-types/record.md#positional-syntax-for-property-definition), use a primary constructor to initialize positional properties. If any of those properties include the `required` modifier, the primary constructor adds the [`SetsRequiredMembers`](../attributes/general.md#setsrequiredmembers-attribute) attribute. This indicates that the primary constructor initializes all required members. You can write your own constructor with the <xref:System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute?displayProperty=nameWithType> attribute. However, the compiler doesn't verify that these constructors do initialize all required members. Rather, the attribute asserts to the compiler that the constructor does initialize all required members. The `SetsRequiredMembers` attribute adds these rules to constructors:
22
+
Some types, such as [positional records](../builtin-types/record.md#positional-syntax-for-property-and-field-definition), use a primary constructor to initialize positional properties. If any of those properties include the `required` modifier, the primary constructor adds the [`SetsRequiredMembers`](../attributes/general.md#setsrequiredmembers-attribute) attribute. This indicates that the primary constructor initializes all required members. You can write your own constructor with the <xref:System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute?displayProperty=nameWithType> attribute. However, the compiler doesn't verify that these constructors do initialize all required members. Rather, the attribute asserts to the compiler that the constructor does initialize all required members. The `SetsRequiredMembers` attribute adds these rules to constructors:
23
23
24
24
- A constructor that chains to another constructor annotated with the `SetsRequiredMembers` attribute, either `this()`, or `base()`, must also include the `SetsRequiredMembers` attribute. That ensures that callers can correctly use all appropriate constructors.
25
25
- Copy constructors generated for `record` types have the `SetsRequiredMembers` attribute applied if any of the members are `required`.
Copy file name to clipboardExpand all lines: docs/csharp/language-reference/operators/deconstruction.md
+1-1
Original file line number
Diff line number
Diff line change
@@ -23,7 +23,7 @@ In the preceding example, the `Y` and `label` members are discarded. You can spe
23
23
24
24
## Record deconstruction
25
25
26
-
[Record](../builtin-types/record.md) types that have a [primary constructor](../builtin-types/record.md#positional-syntax-for-property-definition) support deconstruction for positional parameters. The compiler synthesizes a `Deconstruct` method that extracts the properties synthesized from positional parameters in the primary constructor. The compiler-synthesized `Deconstruction` method doesn't extract properties declared as properties in the record type.
26
+
[Record](../builtin-types/record.md) types that have a [primary constructor](../builtin-types/record.md#positional-syntax-for-property-and-field-definition) support deconstruction for positional parameters. The compiler synthesizes a `Deconstruct` method that extracts the properties synthesized from positional parameters in the primary constructor. The compiler-synthesized `Deconstruction` method doesn't extract properties declared as properties in the record type.
27
27
28
28
The `record` shown in the following code declares two positional properties, `SquareFeet` and `Address`, along with another property, `RealtorNotes`:
The preceding example uses [positional records](../builtin-types/record.md#positional-syntax-for-property-definition) that implicitly provide the `Deconstruct` method.
229
+
The preceding example uses [positional records](../builtin-types/record.md#positional-syntax-for-property-and-field-definition) that implicitly provide the `Deconstruct` method.
230
230
231
231
- Use a [property pattern](#property-pattern) within a positional pattern, as the following example shows:
You can apply any of the attributes to the property names, using the `property:` target on the attribute. For more information on positional records, see the article on [records](../../../csharp/language-reference/builtin-types/record.md#positional-syntax-for-property-definition) in the C# language reference.
47
+
You can apply any of the attributes to the property names, using the `property:` target on the attribute. For more information on positional records, see the article on [records](../../../csharp/language-reference/builtin-types/record.md#positional-syntax-for-property-and-field-definition) in the C# language reference.
0 commit comments