From f23f7a0f0aa7463483fabb04e7e01949fae7f08e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 1 Jul 2021 16:08:39 -0400 Subject: [PATCH 1/5] Add information on sealed ToString Fixes #24077 Beginning in C# 10.0, records may declare a `ToString` method as `sealed`. This prevents derived records from creating an override. Effectively, that means the `ToString` output will not include the runtime type information. (All members and values are displayed, because derived records will still have a PrintMembers method generated.) --- docs/csharp/language-reference/builtin-types/record.md | 7 +++++-- docs/csharp/whats-new/tutorials/records.md | 4 +++- .../tutorials/snippets/record-types/record-types.csproj | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/record.md b/docs/csharp/language-reference/builtin-types/record.md index bba9566da2bb2..a5a2617ff78f5 100644 --- a/docs/csharp/language-reference/builtin-types/record.md +++ b/docs/csharp/language-reference/builtin-types/record.md @@ -1,7 +1,7 @@ --- title: "Records - C# reference" description: Learn about the record type in C# -ms.date: 02/25/2021 +ms.date: 07/01/2021 f1_keywords: - "record_CSharpKeyword" helpviewer_keywords: @@ -136,7 +136,7 @@ The `ToString` override creates a object with t :::code language="csharp" source="snippets/shared/RecordType.cs" id="ToStringOverrideDefault"::: -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. +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 beyond, your implementation may include the `sealed` modifier, which prevents the compiler from synthesizing a `ToString` implementation for any derived records. ## Inheritance @@ -185,6 +185,9 @@ Here is an example of code that replaces the synthesized `PrintMembers` methods, :::code language="csharp" source="snippets/shared/RecordType.cs" id="PrintMembersImplementation"::: +> [!NOTE] +> In C# 1.0 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` as well. + ### Deconstructor behavior in derived records The `Deconstruct` method of a derived record returns the values of all positional properties of the compile-time type. If the variable type is a base record, only the base record properties are deconstructed unless the object is cast to the derived type. The following example demonstrates calling a deconstructor on a derived record. diff --git a/docs/csharp/whats-new/tutorials/records.md b/docs/csharp/whats-new/tutorials/records.md index dd58a59807abf..c25986ca58c70 100644 --- a/docs/csharp/whats-new/tutorials/records.md +++ b/docs/csharp/whats-new/tutorials/records.md @@ -1,7 +1,7 @@ --- title: Use record types - C# tutorial description: Learn about how to use record types, build hierarchies of records, and when to choose records over classes. -ms.date: 11/12/2020 +ms.date: 07/01/2021 --- # Create record types @@ -125,6 +125,8 @@ You declare a `PrintMembers` method in the `DegreeDays` record that doesn't prin The signature declares a `virtual protected` method to match the compiler's version. Don't worry if you get the accessors wrong; the language enforces the correct signature. If you forget the correct modifiers for any synthesized method, the compiler issues warnings or errors that help you get the right signature. +In C# 10.0 and later, you can declare the `ToString` method as `sealed` in a record type. That prevents derived records from providing a new implementation. Derived records will still contain the `PrintMembers` override. You would do this if you didn't want the runtime type of the record displayed by the `ToString` method. In this hierarchy, you'd lose the information on where the record was measuring heating or cooling degree days. + ## Non-destructive mutation The synthesized members in a positional record don't modify the state of the record. The goal is that you can more easily create immutable records. Look again at the preceding declarations for `HeatingDegreeDays` and `CoolingDegreeDays`. The members added perform computations on the values for the record, but don't mutate state. Positional records make it easier for you to create immutable reference types. diff --git a/docs/csharp/whats-new/tutorials/snippets/record-types/record-types.csproj b/docs/csharp/whats-new/tutorials/snippets/record-types/record-types.csproj index 5d38b2381cbf9..0a4163c9e5e77 100644 --- a/docs/csharp/whats-new/tutorials/snippets/record-types/record-types.csproj +++ b/docs/csharp/whats-new/tutorials/snippets/record-types/record-types.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 record_types From 8acedd01c0f70b5e65cf7fc7429aa0a3db3e9b33 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 1 Jul 2021 16:10:25 -0400 Subject: [PATCH 2/5] add note on ToString. --- docs/csharp/language-reference/builtin-types/record.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/language-reference/builtin-types/record.md b/docs/csharp/language-reference/builtin-types/record.md index a5a2617ff78f5..e0aa438fe68f6 100644 --- a/docs/csharp/language-reference/builtin-types/record.md +++ b/docs/csharp/language-reference/builtin-types/record.md @@ -136,7 +136,7 @@ The `ToString` override creates a object with t :::code language="csharp" source="snippets/shared/RecordType.cs" id="ToStringOverrideDefault"::: -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 beyond, your implementation may include the `sealed` modifier, which prevents the compiler from synthesizing a `ToString` implementation for any derived records. +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 beyond, your implementation may include the `sealed` modifier, which prevents the compiler from synthesizing a `ToString` implementation for any derived records. Effectively, that means the `ToString` output will not include the runtime type information. (All members and values are displayed, because derived records will still have a PrintMembers method generated.) ## Inheritance From 6846e5ef6af7d25eed46b4185671d61ebcee2951 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Thu, 1 Jul 2021 16:13:54 -0400 Subject: [PATCH 3/5] fix a build warning introduced This was introduced in an earlier PR --- docs/csharp/language-reference/attributes/general.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/csharp/language-reference/attributes/general.md b/docs/csharp/language-reference/attributes/general.md index e70b0a6cc1b5f..0eb6d32d2418f 100644 --- a/docs/csharp/language-reference/attributes/general.md +++ b/docs/csharp/language-reference/attributes/general.md @@ -47,7 +47,6 @@ In C# 10, you can use constant string interpolation and the `nameof` operator to :::code language="csharp" source="snippets/ObsoleteExample.cs" id="Snippet2" ::: - ## `AttributeUsage` attribute The `AttributeUsage` attribute determines how a custom attribute class can be used. is an attribute you apply to custom attribute definitions. The `AttributeUsage` attribute enables you to control: From 98e97919a95d28c46d031447f64687b7c7e24316 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Fri, 2 Jul 2021 10:11:59 -0400 Subject: [PATCH 4/5] Update docs/csharp/language-reference/builtin-types/record.md Co-authored-by: Youssef Victor --- docs/csharp/language-reference/builtin-types/record.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/language-reference/builtin-types/record.md b/docs/csharp/language-reference/builtin-types/record.md index e0aa438fe68f6..fe9bc0de9307c 100644 --- a/docs/csharp/language-reference/builtin-types/record.md +++ b/docs/csharp/language-reference/builtin-types/record.md @@ -186,7 +186,7 @@ Here is an example of code that replaces the synthesized `PrintMembers` methods, :::code language="csharp" source="snippets/shared/RecordType.cs" id="PrintMembersImplementation"::: > [!NOTE] -> In C# 1.0 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` as well. +> In C# 10.0 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` as well. ### Deconstructor behavior in derived records From 2b8b80c1c7846f74fb620254af5ce845a780a30f Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 6 Jul 2021 13:46:13 -0400 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Tom Dykstra --- docs/csharp/language-reference/builtin-types/record.md | 4 ++-- docs/csharp/whats-new/tutorials/records.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/csharp/language-reference/builtin-types/record.md b/docs/csharp/language-reference/builtin-types/record.md index fe9bc0de9307c..d468a7b8781ca 100644 --- a/docs/csharp/language-reference/builtin-types/record.md +++ b/docs/csharp/language-reference/builtin-types/record.md @@ -136,7 +136,7 @@ The `ToString` override creates a object with t :::code language="csharp" source="snippets/shared/RecordType.cs" id="ToStringOverrideDefault"::: -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 beyond, your implementation may include the `sealed` modifier, which prevents the compiler from synthesizing a `ToString` implementation for any derived records. Effectively, that means the `ToString` output will not include the runtime type information. (All members and values are displayed, because derived records will still have a PrintMembers method generated.) +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 will not include the runtime type information. (All members and values are displayed, because derived records will still have a PrintMembers method generated.) ## Inheritance @@ -186,7 +186,7 @@ Here is an example of code that replaces the synthesized `PrintMembers` methods, :::code language="csharp" source="snippets/shared/RecordType.cs" id="PrintMembersImplementation"::: > [!NOTE] -> In C# 10.0 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` as well. +> In C# 10.0 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`. ### Deconstructor behavior in derived records diff --git a/docs/csharp/whats-new/tutorials/records.md b/docs/csharp/whats-new/tutorials/records.md index c25986ca58c70..9894f653d4390 100644 --- a/docs/csharp/whats-new/tutorials/records.md +++ b/docs/csharp/whats-new/tutorials/records.md @@ -125,7 +125,7 @@ You declare a `PrintMembers` method in the `DegreeDays` record that doesn't prin The signature declares a `virtual protected` method to match the compiler's version. Don't worry if you get the accessors wrong; the language enforces the correct signature. If you forget the correct modifiers for any synthesized method, the compiler issues warnings or errors that help you get the right signature. -In C# 10.0 and later, you can declare the `ToString` method as `sealed` in a record type. That prevents derived records from providing a new implementation. Derived records will still contain the `PrintMembers` override. You would do this if you didn't want the runtime type of the record displayed by the `ToString` method. In this hierarchy, you'd lose the information on where the record was measuring heating or cooling degree days. +In C# 10.0 and later, you can declare the `ToString` method as `sealed` in a record type. That prevents derived records from providing a new implementation. Derived records will still contain the `PrintMembers` override. You would do this if you didn't want the `ToString` method to display the runtime type of the record. In the preceding example, you'd lose the information on where the record was measuring heating or cooling degree days. ## Non-destructive mutation