From e15182424e0accb469b3f3ff4125619249952fe5 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 15:02:44 -0500 Subject: [PATCH 01/10] Remove C# 11 "What's new" Remove the "What's new in C# 11 article, and consolidate with the C# version history. --- .openpublishing.redirection.csharp.json | 10 +- docs/core/whats-new/dotnet-7.md | 2 +- docs/csharp/language-reference/index.yml | 2 - .../language-reference/language-versioning.md | 2 +- docs/csharp/toc.yml | 22 +- docs/csharp/tour-of-csharp/index.yml | 2 - docs/csharp/whats-new/csharp-11.md | 197 ------------------ .../whats-new/csharp-version-history.md | 47 +++-- 8 files changed, 47 insertions(+), 237 deletions(-) delete mode 100644 docs/csharp/whats-new/csharp-11.md diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index 45dc2b1d642b0..02fb64f9c1222 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -349,10 +349,6 @@ "source_path_from_root": "/docs/csharp/getting-started/testing-library-with-visual-studio.md", "redirect_url": "/dotnet/core/tutorials/testing-library-with-visual-studio" }, - { - "source_path_from_root": "/docs/csharp/getting-started/whats-new.md", - "redirect_url": "/dotnet/csharp/whats-new/csharp-11" - }, { "source_path_from_root": "/docs/csharp/getting-started/with-visual-studio-2017.md", "redirect_url": "/dotnet/core/tutorials/with-visual-studio", @@ -5004,9 +5000,13 @@ "source_path_from_root": "/docs/csharp/whats-new/csharp-10.md", "redirect_url": "/dotnet/csharp/whats-new/csharp-version-history#c-version-10" }, + { + "source_path_from_root": "/docs/csharp/whats-new/csharp-11.md", + "redirect_url": "/dotnet/csharp/whats-new/csharp-version-history#c-version-11" + }, { "source_path_from_root": "/docs/csharp/whats-new/index.md", - "redirect_url": "/dotnet/csharp/whats-new/csharp-13", + "redirect_url": "/dotnet/csharp/whats-new/csharp-14", "ms.custom": "updateeachrelease" }, { diff --git a/docs/core/whats-new/dotnet-7.md b/docs/core/whats-new/dotnet-7.md index ce56acaee5c35..0ac6f37b2ab58 100644 --- a/docs/core/whats-new/dotnet-7.md +++ b/docs/core/whats-new/dotnet-7.md @@ -129,7 +129,7 @@ For more information, see [What's new in Visual Studio 2022](/visualstudio/ide/w ### C# 11 -C# 11 includes support for [generic math](../../standard/generics/math.md), raw string literals, file-scoped types, and other new features. For more information, see [What's new in C# 11](../../csharp/whats-new/csharp-11.md). +C# 11 includes support for [generic math](../../standard/generics/math.md), raw string literals, file-scoped types, and other new features. For more information, see [What's new in C# 11](../../csharp/whats-new/csharp-version-history.md#c-version-11). ### F# 7 diff --git a/docs/csharp/language-reference/index.yml b/docs/csharp/language-reference/index.yml index fda5fb062f875..4b416a5ee55a6 100644 --- a/docs/csharp/language-reference/index.yml +++ b/docs/csharp/language-reference/index.yml @@ -37,8 +37,6 @@ landingContent: url: ../whats-new/csharp-13.md - text: "What's new in C# 12" url: ../whats-new/csharp-12.md - - text: "What's new in C# 11" - url: ../whats-new/csharp-11.md - linkListType: reference links: - text: Breaking changes in the C# compiler diff --git a/docs/csharp/language-reference/language-versioning.md b/docs/csharp/language-reference/language-versioning.md index 54b9e4832dd47..18d9290927625 100644 --- a/docs/csharp/language-reference/language-versioning.md +++ b/docs/csharp/language-reference/language-versioning.md @@ -9,7 +9,7 @@ ms.date: 09/17/2024 The latest C# compiler determines a default language version based on your project's target framework or frameworks. Visual Studio doesn't provide a UI to change the value, but you can change it by editing the *csproj* file. The choice of default ensures that you use the latest language version compatible with your target framework. You benefit from access to the latest language features compatible with your project's target. This default choice also ensures you don't use a language that requires types or runtime behavior not available in your target framework. Choosing a language version newer than the default can cause hard to diagnose compile-time and runtime errors. -[C# 13](../whats-new/csharp-13.md) is supported only on .NET 9 and newer versions. [C# 12](../whats-new/csharp-12.md) is supported only on .NET 8 and newer versions. [C# 11](../whats-new/csharp-11.md) is supported only on .NET 7 and newer versions. Using a C# language version newer than the version associated with your target TFM is unsupported. +[C# 14](../whats-new/csharp-14.md) is supported only on .NET 10 and newer versions. [C# 13](../whats-new/csharp-13.md) is supported only on .NET 9 and newer versions. [C# 12](../whats-new/csharp-12.md) is supported only on .NET 8 and newer versions. Using a C# language version newer than the version associated with your target TFM is unsupported. Check the [Visual Studio platform compatibility](/visualstudio/releases/2022/compatibility#-visual-studio-2022-support-for-net-development) page for details on which .NET versions are supported by versions of Visual Studio. Check the [Mono page for C#](https://www.mono-project.com/docs/about-mono/languages/csharp/) for Mono compatibility with C# versions. diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index 603de70069257..52e8b95da8f8e 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -146,28 +146,26 @@ items: items: - name: What's new in C# 14 href: whats-new/csharp-14.md - - name: Breaking changes since C# 13 - href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2010.md - name: C# 13 items: - name: What's new in C# 13 href: whats-new/csharp-13.md - - name: Breaking changes since C# 12 - href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%209.md - name: C# 12 items: - name: What's new in C# 12 href: whats-new/csharp-12.md - - name: Breaking changes since C# 11 - href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%208.md - - name: C# 11 + - name: Breaking changes items: - - name: What's new C# 11 - href: whats-new/csharp-11.md - - name: Breaking changes since C# 10 + - name: After C# 13 + href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2010.md + - name: After C# 12 + href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%209.md + - name: After C# 11 + href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%208.md + - name: After C# 10 href: ../../_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%207.md - - name: Breaking before C# 10 - href: whats-new/breaking-changes.md + - name: Breaking before C# 10 + href: whats-new/breaking-changes.md - name: C# version history href: whats-new/csharp-version-history.md - name: Relationships to .NET library diff --git a/docs/csharp/tour-of-csharp/index.yml b/docs/csharp/tour-of-csharp/index.yml index 5cf2d9f98229b..56fc662e834fa 100644 --- a/docs/csharp/tour-of-csharp/index.yml +++ b/docs/csharp/tour-of-csharp/index.yml @@ -89,8 +89,6 @@ landingContent: url: ../whats-new/csharp-13.md - text: "What's new in C# 12" url: ../whats-new/csharp-12.md - - text: "What's new in C# 11" - url: ../whats-new/csharp-11.md - linkListType: tutorial links: - text: Explore record types diff --git a/docs/csharp/whats-new/csharp-11.md b/docs/csharp/whats-new/csharp-11.md deleted file mode 100644 index 0fdf357bf2bf7..0000000000000 --- a/docs/csharp/whats-new/csharp-11.md +++ /dev/null @@ -1,197 +0,0 @@ ---- -title: What's new in C# 11 -description: Get an overview of the new features added in C# 11. -ms.date: 03/15/2024 -ms.topic: whats-new ---- -# What's new in C# 11 - -The following features were added in C# 11: - -- [Raw string literals](#raw-string-literals) -- [Generic math support](#generic-math-support) -- [Generic attributes](#generic-attributes) -- [UTF-8 string literals](#utf-8-string-literals) -- [Newlines in string interpolation expressions](#newlines-in-string-interpolations) -- [List patterns](#list-patterns) -- [File-local types](#file-local-types) -- [Required members](#required-members) -- [Auto-default structs](#auto-default-struct) -- [Pattern match `Span` on a constant `string`](#pattern-match-spanchar-or-readonlyspanchar-on-a-constant-string) -- [Extended `nameof` scope](#extended-nameof-scope) -- [Numeric IntPtr](#numeric-intptr-and-uintptr) -- [`ref` fields and `scoped ref`](#ref-fields-and-ref-scoped-variables) -- [Improved method group conversion to delegate](#improved-method-group-conversion-to-delegate) -- [Warning wave 7](../language-reference/compiler-messages/warning-waves.md#cs8981---the-type-name-only-contains-lower-cased-ascii-characters) - -C# 11 is supported on **.NET 7**. For more information, see [C# language versioning](../language-reference/configure-language-version.md). - -You can download the latest .NET 7 SDK from the [.NET downloads page](https://dotnet.microsoft.com/download). You can also download [Visual Studio 2022](https://visualstudio.microsoft.com/vs/), which includes the .NET 7 SDK. - -[!INCLUDE [released-version-feedback](./includes/released-feedback.md)] - -## Generic attributes - -You can declare a [generic class](../programming-guide/generics/generic-classes.md) whose base class is . This feature provides a more convenient syntax for attributes that require a parameter. Previously, you'd need to create an attribute that takes a `Type` as its constructor parameter: - -```csharp -// Before C# 11: -public class TypeAttribute : Attribute -{ - public TypeAttribute(Type t) => ParamType = t; - - public Type ParamType { get; } -} -``` - -And to apply the attribute, you use the [`typeof`](../language-reference/operators/type-testing-and-cast.md#the-typeof-operator) operator: - -```csharp -[TypeAttribute(typeof(string))] -public string Method() => default; -``` - -Using this new feature, you can create a generic attribute instead: - -```csharp -// C# 11 feature: -public class GenericAttribute : Attribute { } -``` - -Then, specify the type parameter to use the attribute: - -```csharp -[GenericAttribute()] -public string Method() => default; -``` - -You must supply all type parameters when you apply the attribute. In other words, the generic type must be [fully constructed](~/_csharpstandard/standard/types.md#84-constructed-types). -In the example above, the empty parentheses (`(` and `)`) can be omitted as the attribute does not have any arguments. - -```csharp -public class GenericType -{ - [GenericAttribute()] // Not allowed! generic attributes must be fully constructed types. - public string Method() => default; -} -``` - -The type arguments must satisfy the same restrictions as the [`typeof`](../language-reference/operators/type-testing-and-cast.md#the-typeof-operator) operator. Types that require metadata annotations aren't allowed. For example, the following types aren't allowed as the type parameter: - -- `dynamic` -- `string?` (or any nullable reference type) -- `(int X, int Y)` (or any other tuple types using C# tuple syntax). - -These types aren't directly represented in metadata. They include annotations that describe the type. In all cases, you can use the underlying type instead: - -- `object` for `dynamic`. -- `string` instead of `string?`. -- `ValueTuple` instead of `(int X, int Y)`. - -## Generic math support - -There are several language features that enable generic math support: - -- `static virtual` members in interfaces -- checked user defined operators -- relaxed shift operators -- unsigned right-shift operator - -You can add `static abstract` or `static virtual` members in interfaces to define interfaces that include overloadable operators, other static members, and static properties. The primary scenario for this feature is to use mathematical operators in generic types. For example, you can implement the `System.IAdditionOperators` interface in a type that implements `operator +`. Other interfaces define other mathematical operations or well-defined values. You can learn about the new syntax in the article on [interfaces](../language-reference/keywords/interface.md#static-abstract-and-virtual-members). Interfaces that include `static virtual` methods are typically [generic interfaces](../programming-guide/generics/generic-interfaces.md). Furthermore, most will declare a constraint that the type parameter [implements the declared interface](../programming-guide/generics/constraints-on-type-parameters.md#type-arguments-implement-declared-interface). - -You can learn more and try the feature yourself in the tutorial [Explore static abstract interface members](./tutorials/static-virtual-interface-members.md), or the [Preview features in .NET 6 – generic math](https://devblogs.microsoft.com/dotnet/preview-features-in-net-6-generic-math/) blog post. - -Generic math created other requirements on the language. - -- *unsigned right shift operator*: Before C# 11, to force an unsigned right-shift, you would need to cast any signed integer type to an unsigned type, perform the shift, then cast the result back to a signed type. Beginning in C# 11, you can use the `>>>`, the [*unsigned shift operator*](../language-reference/operators/bitwise-and-shift-operators.md#unsigned-right-shift-operator-). -- *relaxed shift operator requirements*: C# 11 removes the requirement that the second operand must be an `int` or implicitly convertible to `int`. This change allows types that implement generic math interfaces to be used in these locations. -- *checked and unchecked user defined operators*: Developers can now define `checked` and `unchecked` arithmetic operators. The compiler generates calls to the correct variant based on the current context. You can read more about `checked` operators in the article on [Arithmetic operators](../language-reference/operators/arithmetic-operators.md). - -## Numeric `IntPtr` and `UIntPtr` - -The `nint` and `nuint` types now alias and , respectively. - -## Newlines in string interpolations - -The text inside the `{` and `}` characters for a string interpolation can now span multiple lines. The text between the `{` and `}` markers is parsed as C#. Any legal C#, including newlines, is allowed. This feature makes it easier to read string interpolations that use longer C# expressions, like pattern matching `switch` expressions, or LINQ queries. - -You can learn more about the newlines feature in the [string interpolations](../language-reference/tokens/interpolated.md) article in the language reference. - -## List patterns - -*List patterns* extend pattern matching to match sequences of elements in a list or an array. For example, `sequence is [1, 2, 3]` is `true` when the `sequence` is an array or a list of three integers (1, 2, and 3). You can match elements using any pattern, including constant, type, property and relational patterns. The discard pattern (`_`) matches any single element, and the new *range pattern* (`..`) matches any sequence of zero or more elements. - -You can learn more details about list patterns in the [pattern matching](../language-reference/operators/patterns.md#list-patterns) article in the language reference. - -## Improved method group conversion to delegate - -The C# standard on [Method group conversions](~/_csharpstandard/standard/conversions.md#108-method-group-conversions) now includes the following item: - -> - The conversion is permitted (but not required) to use an existing delegate instance that already contains these references. - -Previous versions of the standard prohibited the compiler from reusing the delegate object created for a method group conversion. The C# 11 compiler caches the delegate object created from a method group conversion and reuses that single delegate object. This feature was first available in Visual Studio 2022 version 17.2 as a preview feature, and in .NET 7 Preview 2. - -## Raw string literals - -*Raw string literals* are a new format for string literals. Raw string literals can contain arbitrary text, including whitespace, new lines, embedded quotes, and other special characters without requiring escape sequences. A raw string literal starts with at least three double-quote (""") characters. It ends with the same number of double-quote characters. Typically, a raw string literal uses three double quotes on a single line to start the string, and three double quotes on a separate line to end the string. The newlines following the opening quote and preceding the closing quote aren't included in the final content: - -```csharp -string longMessage = """ - This is a long message. - It has several lines. - Some are indented - more than others. - Some should start at the first column. - Some have "quoted text" in them. - """; -``` - -Any whitespace to the left of the closing double quotes will be removed from the string literal. Raw string literals can be combined with string interpolation to include braces in the output text. Multiple `$` characters denote how many consecutive braces start and end the interpolation: - -```csharp -var location = $$""" - You are at {{{Longitude}}, {{Latitude}}} - """; -``` - -The preceding example specifies that two braces start and end an interpolation. The third repeated opening and closing brace are included in the output string. - -You can learn more about raw string literals in the article on [strings in the programming guide](../programming-guide/strings/index.md), and the language reference articles on [string literals](../language-reference/builtin-types/reference-types.md#string-literals) and [interpolated strings](../language-reference/tokens/interpolated.md). - -## Auto-default struct - -The C# 11 compiler ensures that all fields of a `struct` type are initialized to their default value as part of executing a constructor. This change means any field or auto property not initialized by a constructor is automatically initialized by the compiler. Structs where the constructor doesn't definitely assign all fields now compile, and any fields not explicitly initialized are set to their default value. You can read more about how this change affects struct initialization in the article on [structs](../language-reference/builtin-types/struct.md#struct-initialization-and-default-values). - -## Pattern match `Span` or `ReadOnlySpan` on a constant `string` - -You've been able to test if a `string` had a specific constant value using pattern matching for several releases. Now, you can use the same pattern matching logic with variables that are `Span` or `ReadOnlySpan`. - -## Extended nameof scope - -Type parameter names and parameter names are now in scope when used in a `nameof` expression in an [attribute declaration](/dotnet/csharp/advanced-topics/reflection-and-attributes#using-attributes) on that method. This feature means you can use the `nameof` operator to specify the name of a method parameter in an attribute on the method or parameter declaration. This feature is most often useful to add attributes for [nullable analysis](../language-reference/attributes/nullable-analysis.md). - -## UTF-8 string literals - -You can specify the `u8` suffix on a string literal to specify UTF-8 character encoding. If your application needs UTF-8 strings, for HTTP string constants or similar text protocols, you can use this feature to simplify the creation of UTF-8 strings. - -You can learn more about UTF-8 string literals in the string literal section of the article on [builtin reference types](../language-reference/builtin-types/reference-types.md#utf-8-string-literals). - -## Required members - -You can add the [`required` modifier](../language-reference/keywords/required.md) to properties and fields to enforce constructors and callers to initialize those values. The can be added to constructors to inform the compiler that a constructor initializes *all* required members. - -For more information on required members, See the [Required properties](../programming-guide/classes-and-structs/properties.md#required-properties) section of the properties article. - -## `ref` fields and `ref scoped` variables - -You can declare `ref` fields inside a [`ref struct`](../language-reference/builtin-types/ref-struct.md). This supports types such as without special attributes or hidden internal types. - -You can add the [`scoped`](../language-reference/statements/declarations.md#scoped-ref) modifier to any `ref` declaration. This limits the [scope](../language-reference/keywords/method-parameters.md#safe-context-of-references-and-values) where the reference can escape to. - -## File local types - -Beginning in C# 11, you can use the `file` access modifier to create a type whose visibility is scoped to the source file in which it is declared. This feature helps source generator authors avoid naming collisions. You can learn more about this feature in the article on [file-scoped types](../language-reference/keywords/file.md) in the language reference. - -## See also - -- [What's new in .NET 7](../../core/whats-new/dotnet-7.md) diff --git a/docs/csharp/whats-new/csharp-version-history.md b/docs/csharp/whats-new/csharp-version-history.md index 30dbe02f6ebf6..0d15abf11c656 100644 --- a/docs/csharp/whats-new/csharp-version-history.md +++ b/docs/csharp/whats-new/csharp-version-history.md @@ -2,7 +2,7 @@ title: The history of C# description: Learn how the C# language has changed over its many releases. Learn when different features were introduced in the language. author: erikdietrich -ms.date: 12/20/2024 +ms.date: 11/18/2025 ms.custom: "updateeachrelease" --- @@ -13,6 +13,21 @@ This article provides a history of each major release of the C# language. The C# > [!IMPORTANT] > The C# language relies on types and methods in what the C# specification defines as a *standard library* for some of the features. The .NET platform delivers those types and methods in a number of packages. One example is exception processing. Every `throw` statement or expression is checked to ensure the object being thrown is derived from . Similarly, every `catch` is checked to ensure that the type being caught is derived from . Each version may add new requirements. To use the latest language features in older environments, you may need to install specific libraries. These dependencies are documented in the page for each specific version. You can learn more about the [relationships between language and library](relationships-between-language-and-library.md) for background on this dependency. +## C# version 14 + +*Released November 2025* + +C# 14 includes the following new features: + +- [Extension members](./csharp14.md#extension-members) +- [Null-conditional assignment](./csharp14.md#null-conditional-assignment) +- [`nameof` supports unbound generic types](./csharp14.md#unbound-generic-types-and-nameof) +- [More implicit conversions for `Span` and `ReadOnlySpan`](./csharp14.md#implicit-span-conversions) +- [Modifiers on simple lambda parameters](./csharp14.md#simple-lambda-parameters-with-modifiers) +- [`field` backed properties](./csharp14.md#the-field-keyword) +- [`partial` events and constructors](./csharp14.md#more-partial-members) +- [user-defined compound assignment operators](./csharp14.md#user-defined-compound-assignment) + ## C# version 13 *Released November 2024* @@ -30,8 +45,6 @@ C# 13 includes the following new features: - Partial properties and indexers are now allowed in `partial` types. - Overload resolution priority allows library authors to designate one overload as better than others. -And, the `field` contextual keyword to access the compiler generated backing field in an automatically implemented property was released as a preview feature. - ## C# version 12 *Released November 2023* @@ -56,20 +69,20 @@ Overall, C# 12 provides new features that make you more productive writing C# co The following features were added in C# 11: -- [Raw string literals](./csharp-11.md#raw-string-literals) -- [Generic math support](./csharp-11.md#generic-math-support) -- [Generic attributes](./csharp-11.md#generic-attributes) -- [UTF-8 string literals](./csharp-11.md#utf-8-string-literals) -- [Newlines in string interpolation expressions](./csharp-11.md#newlines-in-string-interpolations) -- [List patterns](./csharp-11.md#list-patterns) -- [File-local types](./csharp-11.md#file-local-types) -- [Required members](./csharp-11.md#required-members) -- [Auto-default structs](./csharp-11.md#auto-default-struct) -- [Pattern match `Span` on a constant `string`](./csharp-11.md#pattern-match-spanchar-or-readonlyspanchar-on-a-constant-string) -- [Extended `nameof` scope](./csharp-11.md#extended-nameof-scope) -- [Numeric IntPtr](./csharp-11.md#numeric-intptr-and-uintptr) -- [`ref` fields and `scoped ref`](./csharp-11.md#ref-fields-and-ref-scoped-variables) -- [Improved method group conversion to delegate](./csharp-11.md#improved-method-group-conversion-to-delegate) +- [Raw string literals](../language-reference/builtin-types/reference-types.md#string-literals). +- [Generic math support](../language-reference/keywords/interface.md#static-abstract-and-virtual-members). +- [Generic attributes](../advanced-topics/reflection-and-attributes/creating-custom-attributes.md). +- [UTF-8 string literals](../language-reference/builtin-types/reference-types.md#utf-8-string-literals). +- [Newlines in string interpolation expressions](../language-reference/tokens/interpolated.md). +- [List patterns](../language-reference/operators/patterns.md#list-patterns). +- [File-local types](../language-reference/keywords/file.md). +- [Required members](../programming-guide/classes-and-structs/properties.md#required-properties). +- [Auto-default structs](../language-reference/builtin-types/struct.md#struct-initialization-and-default-values). +- Pattern match `Span` on a constant `string`. +- Extended `nameof` scope. +- The `nint` and `uint` keywords alias and , respectively. +- [`ref` fields and `scoped ref`](../language-reference/builtin-types/ref-struct.md#ref-fields) +- Improved method group conversion to delegate. - [Warning wave 7](../language-reference/compiler-messages/warning-waves.md#cs8981---the-type-name-only-contains-lower-cased-ascii-characters) C# 11 introduces *generic math* and several features that support that goal. You can write numeric algorithms once for all number types. There's more features to make working with `struct` types easier, like required members and auto-default structs. Working with strings gets easier with Raw string literals, newline in string interpolations, and UTF-8 string literals. Features like file local types enable source generators to be simpler. Finally, list patterns add more support for pattern matching. From dd40c3b9f2400aaef0deb11376241f9a9642e53e Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 16:42:58 -0500 Subject: [PATCH 02/10] Remove references to C# 11 "new" Removing all phrasing that indicates when a feature was added in C# 11. Update date and perform an edit and review pass. --- .../generics-and-attributes.md | 4 +- .../conceptual/GenericsAndAttributes.cs | 2 +- .../functional/pattern-matching.md | 4 +- docs/csharp/fundamentals/types/interfaces.md | 12 +-- .../attributes/caller-information.md | 14 ++-- .../attributes/nullable-analysis.md | 80 +++++++++---------- .../builtin-types/default-values.md | 6 +- .../builtin-types/integral-numeric-types.md | 28 +++---- .../builtin-types/ref-struct.md | 8 +- .../builtin-types/reference-types.md | 10 +-- .../builtin-types/struct.md | 10 +-- .../language-reference/keywords/file.md | 14 ++-- .../language-reference/keywords/interface.md | 18 ++--- .../operators/addition-operator.md | 4 +- .../operators/arithmetic-operators.md | 12 +-- .../operators/bitwise-and-shift-operators.md | 12 +-- .../operators/delegate-operator.md | 10 +-- .../csharp/language-reference/operators/is.md | 4 +- .../language-reference/operators/nameof.md | 6 +- .../language-reference/operators/patterns.md | 20 ++--- .../user-defined-conversion-operators.md | 4 +- .../statements/checked-and-unchecked.md | 6 +- .../language-reference/tokens/interpolated.md | 12 +-- .../language-reference/tokens/raw-string.md | 4 +- .../classes-and-structs/properties.md | 4 +- .../generics/generic-interfaces.md | 4 +- .../csharp/programming-guide/strings/index.md | 6 +- .../tutorials/nullable-reference-types.md | 54 ++++++------- docs/csharp/tutorials/string-interpolation.md | 4 +- .../static-virtual-interface-members.md | 24 +++--- 30 files changed, 197 insertions(+), 203 deletions(-) diff --git a/docs/csharp/advanced-topics/reflection-and-attributes/generics-and-attributes.md b/docs/csharp/advanced-topics/reflection-and-attributes/generics-and-attributes.md index 2aaa139c54512..7f2e0eb459032 100644 --- a/docs/csharp/advanced-topics/reflection-and-attributes/generics-and-attributes.md +++ b/docs/csharp/advanced-topics/reflection-and-attributes/generics-and-attributes.md @@ -1,7 +1,7 @@ --- title: "Generics and attributes" description: Learn about applying attributes to generic types. See code examples and view more available resources. -ms.date: 03/15/2023 +ms.date: 11/18/2025 helpviewer_keywords: - "generics [C#], attributes" - "attributes [C#], with generics" @@ -33,7 +33,7 @@ An attribute that references a generic type parameter causes a compile-time erro class ClassD { } ``` -Beginning with C# 11, a generic type can inherit from : +A generic type can inherit from : :::code language="csharp" source="./snippets/conceptual/GenericsAndAttributes.cs" id="GenericAttribute"::: diff --git a/docs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.cs b/docs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.cs index a0e7a26df35a1..7093257f458aa 100644 --- a/docs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.cs +++ b/docs/csharp/advanced-topics/reflection-and-attributes/snippets/conceptual/GenericsAndAttributes.cs @@ -30,5 +30,5 @@ class ClassC { } // // -public class CustomGenericAttribute : Attribute { } //Requires C# 11 +public class CustomGenericAttribute : Attribute { } // diff --git a/docs/csharp/fundamentals/functional/pattern-matching.md b/docs/csharp/fundamentals/functional/pattern-matching.md index 10d003d230d4f..f2f5f7cb8dd46 100644 --- a/docs/csharp/fundamentals/functional/pattern-matching.md +++ b/docs/csharp/fundamentals/functional/pattern-matching.md @@ -1,7 +1,7 @@ --- title: Pattern matching overview description: "Learn about pattern matching expressions in C#" -ms.date: 01/27/2025 +ms.date: 11/18/2025 --- # Pattern matching overview @@ -40,7 +40,7 @@ The previous example demonstrates a method dispatch based on the value of an enu :::code language="csharp" source="snippets/patterns/Simulation.cs" ID="PerformStringOperation"::: -The preceding example shows the same algorithm, but uses string values instead of an enum. You would use this scenario if your application responds to text commands instead of a regular data format. Starting with C# 11, you can also use a `Span` or a `ReadOnlySpan`to test for constant string values, as shown in the following sample: +The preceding example shows the same algorithm, but uses string values instead of an enum. You would use this scenario if your application responds to text commands instead of a regular data format. You can also use a `Span` or a `ReadOnlySpan`to test for constant string values, as shown in the following sample: :::code language="csharp" source="snippets/patterns/Simulation.cs" ID="PerformSpanOperation"::: diff --git a/docs/csharp/fundamentals/types/interfaces.md b/docs/csharp/fundamentals/types/interfaces.md index 7228c8a09faec..e2923687f6290 100644 --- a/docs/csharp/fundamentals/types/interfaces.md +++ b/docs/csharp/fundamentals/types/interfaces.md @@ -1,7 +1,7 @@ --- title: "Interfaces - define behavior for multiple types" description: An interface in C# contains definitions for a group of related functionalities that a non-abstract class or a struct must implement. It specifies the members and their signatures for a type that implements the interface. -ms.date: 10/13/2025 +ms.date: 11/18/2025 helpviewer_keywords: - "interfaces [C#]" - "C# language, interfaces" @@ -24,12 +24,12 @@ The definition of `IEquatable` doesn't provide an implementation for `Equals` For more information about abstract classes, see [Abstract and Sealed Classes and Class Members](../../programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members.md). -Interfaces can contain instance methods, properties, events, indexers, or any combination of those four member types. Interfaces can contain static constructors, fields, constants, or operators. Beginning with C# 11, interface members that aren't fields can be `static abstract`. An interface can't contain instance fields, instance constructors, or finalizers. Interface members are public by default, and you can explicitly specify accessibility modifiers, such as `public`, `protected`, `internal`, `private`, `protected internal`, or `private protected`. A `private` member must have a default implementation. +Interfaces can contain instance methods, properties, events, indexers, or any combination of those four member types. Interfaces can contain static constructors, fields, constants, or operators. Interface members that aren't fields can be `static abstract`. An interface can't contain instance fields, instance constructors, or finalizers. Interface members are public by default, and you can explicitly specify accessibility modifiers, such as `public`, `protected`, `internal`, `private`, `protected internal`, or `private protected`. A `private` member must have a default implementation. -To implement an interface member using implicit implementation, the corresponding member of the implementing class must be public, non-static, and have the same name and signature as the interface member. However, when an interface is meant to be internal only or uses internal types in its signature, you can use explicit interface implementation instead, which doesn't require the implementing member to be public. +To implement an interface member using implicit implementation, the corresponding member of the implementing class must be public, non-static, and have the same name and signature as the interface member. You must use explicit interface implementation to implement interface members that aren't meant to be public. > [!NOTE] -> When an interface declares static members, a type implementing that interface might also declare static members with the same signature. Those are distinct and uniquely identified by the type declaring the member. The static member declared in a type *doesn't* override the static member declared in the interface. +> When an interface declares static members, a type implementing that interface might also declare static members with the same signature. Those members are distinct and uniquely identified by the type declaring the member. The static member declared in a type *doesn't* override the static member declared in the interface. A class or struct that implements an interface must provide an implementation for all declared members without a default implementation provided by the interface. However, if a base class implements an interface, any class derived from the base class inherits that implementation. @@ -37,7 +37,7 @@ The following example shows an implementation of the property for exceptions, the results aren't affected by obfuscation. You can explicitly supply the optional arguments to control the caller information or to hide caller information. +You specify an explicit default value for each optional parameter. You can't apply caller info attributes to parameters that aren't specified as optional. The caller info attributes don't make a parameter optional. Instead, they affect the default value passed in when the argument is omitted. Caller info values are emitted as literals into the Intermediate Language (IL) at compile time. Unlike the results of the property for exceptions, obfuscation doesn't affect the results. You can explicitly supply the optional arguments to control the caller information or to hide caller information. ## Member names You can use the `CallerMemberName` attribute to avoid specifying the member name as a `String` argument to the called method. By using this technique, you avoid the problem that **Rename Refactoring** doesn't change the `String` values. This benefit is especially useful for the following tasks: - Using tracing and diagnostic routines. -- Implementing the interface when binding data. This interface allows the property of an object to notify a bound control that the property has changed. The control can display the updated information. Without the `CallerMemberName` attribute, you must specify the property name as a literal. +- Implementing the interface when binding data. This interface allows the property of an object to notify a bound control that the property changed. The control can display the updated information. Without the `CallerMemberName` attribute, you must specify the property name as a literal. The following chart shows the member names that are returned when you use the `CallerMemberName` attribute. @@ -37,12 +37,12 @@ The following chart shows the member names that are returned when you use the `C | Static constructor | The string ".cctor" | | Finalizer | The string "Finalize" | | User-defined operators or conversions | The generated name for the member, for example, "op_Addition". | -| Attribute constructor | The name of the method or property to which the attribute is applied. If the attribute is any element within a member (such as a parameter, a return value, or a generic type parameter), this result is the name of the member that's associated with that element. | +| Attribute constructor | The name of the method or property to which the attribute is applied. If the attribute is any element within a member (such as a parameter, a return value, or a generic type parameter), this result is the name of the member associated with that element. | | No containing member (for example, assembly-level or attributes that are applied to types) | The default value of the optional parameter. | ## Argument expressions -You use the when you want the expression passed as an argument. Diagnostic libraries may want to provide more details about the *expressions* passed to arguments. By providing the expression that triggered the diagnostic, in addition to the parameter name, developers have more details about the condition that triggered the diagnostic. That extra information makes it easier to fix. +You use the when you want the expression passed as an argument. Diagnostic libraries can provide more details about the *expressions* passed to arguments. By providing the expression that triggered the diagnostic, in addition to the parameter name, developers have more details about the condition that triggered the diagnostic. That extra information makes it easier to fix. The following example shows how you can provide detailed information about the argument when it's invalid: @@ -52,7 +52,7 @@ You would invoke it as shown in the following example: :::code language="csharp" source="./snippets/CallerInformation.cs" id="InvokeTestCondition"::: -The expression used for `condition` is injected by the compiler into the `message` argument. When a developer calls `Operation` with a `null` argument, the following message is stored in the `ArgumentException`: +The compiler injects the expression used for `condition` into the `message` argument. When a developer calls `Operation` with a `null` argument, the following message is stored in the `ArgumentException`: ```text Argument failed validation: @@ -62,7 +62,7 @@ This attribute enables you to write diagnostic utilities that provide more detai :::code language="csharp" source="./snippets/CallerInformation.cs" id="ExtensionMethod"::: -The previous example uses the [`nameof`](../operators/nameof.md) operator for the parameter `sequence`. That feature is available in C# 11. Before C# 11, you'll need to type the name of the parameter as a string. You could call this method as follows: +The previous example uses the [`nameof`](../operators/nameof.md) operator for the parameter `sequence`. You could call this method as follows: :::code language="csharp" source="./snippets/Program.cs" id="ShortSequence"::: diff --git a/docs/csharp/language-reference/attributes/nullable-analysis.md b/docs/csharp/language-reference/attributes/nullable-analysis.md index 80ee0dab42c10..7bbabe8372aeb 100644 --- a/docs/csharp/language-reference/attributes/nullable-analysis.md +++ b/docs/csharp/language-reference/attributes/nullable-analysis.md @@ -1,20 +1,20 @@ --- title: "Attributes interpreted by the compiler: Nullable static analysis" -description: Learn about attributes that are interpreted by the compiler to provide better static analysis for nullable and non-nullable reference types. -ms.date: 05/20/2022 +description: Learn about attributes interpreted by the compiler to provide better static analysis for nullable and non-nullable reference types. +ms.date: 11/18/2025 --- # Attributes for null-state static analysis interpreted by the C# compiler In a nullable enabled context, the compiler performs static analysis of code to determine the *null-state* of all reference type variables: - *not-null*: Static analysis determines that a variable has a non-null value. -- *maybe-null*: Static analysis can't determine that a variable is assigned a non-null value. +- *maybe-null*: Static analysis can't determine that a variable is assigned to a non-null value. -These states enable the compiler to provide warnings when you may dereference a null value, throwing a . These attributes provide the compiler with semantic information about the *null-state* of arguments, return values, and object members based on the state of arguments and return values. The compiler provides more accurate warnings when your APIs have been properly annotated with this semantic information. +These states enable the compiler to provide warnings when you might dereference a null value, throwing a . These attributes provide the compiler with semantic information about the *null-state* of arguments, return values, and object members. The attributes clarify the state of arguments and return values. The compiler provides more accurate warnings when your APIs are properly annotated with this semantic information. This article provides a brief description of each of the nullable reference type attributes and how to use them. -Let's start with an example. Imagine your library has the following API to retrieve a resource string. This method was originally compiled in a *nullable oblivious* context: +Let's start with an example. Imagine your library has the following API that retrieves a resource string. This method was originally compiled in a *nullable oblivious* context: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="TryGetExample" ::: @@ -24,22 +24,22 @@ The preceding example follows the familiar `Try*` pattern in .NET. There are two - Callers can pass a variable whose value is `null` as the argument for `message`. - If the `TryGetMessage` method returns `true`, the value of `message` isn't null. If the return value is `false`, the value of `message` is null. -The rule for `key` can be expressed succinctly: `key` should be a non-nullable reference type. The `message` parameter is more complex. It allows a variable that is `null` as the argument, but guarantees, on success, that the `out` argument isn't `null`. For these scenarios, you need a richer vocabulary to describe the expectations. The `NotNullWhen` attribute, described below describes the *null-state* for the argument used for the `message` parameter. +The rule for `key` can be expressed succinctly: `key` should be a non-nullable reference type. The `message` parameter is more complex. It allows a variable that is `null` as the argument, but guarantees, on success, that the `out` argument isn't `null`. For these scenarios, you need a richer vocabulary to describe the expectations. The [`NotNullWhen`](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) attribute describes the *null-state* for the argument used for the `message` parameter. > [!NOTE] -> Adding these attributes gives the compiler more information about the rules for your API. When calling code is compiled in a nullable enabled context, the compiler will warn callers when they violate those rules. These attributes don't enable more checks on your implementation. +> Adding these attributes gives the compiler more information about the rules for your API. When calling code is compiled in a nullable enabled context, the compiler warns callers when they violate those rules. These attributes don't enable more checks on your implementation. | Attribute | Category | Meaning | | - | - | - | -| [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute) | [Precondition](#preconditions-allownull-and-disallownull) | A non-nullable parameter, field, or property may be null. | +| [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute) | [Precondition](#preconditions-allownull-and-disallownull) | A non-nullable parameter, field, or property might be null. | | [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute) | [Precondition](#preconditions-allownull-and-disallownull) | A nullable parameter, field, or property should never be null. | -| [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute) | [Postcondition](#postconditions-maybenull-and-notnull) | A non-nullable parameter, field, property, or return value may be null. | -| [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute) | [Postcondition](#postconditions-maybenull-and-notnull) | A nullable parameter, field, property, or return value will never be null. | -| [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A non-nullable argument may be null when the method returns the specified `bool` value. | -| [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A nullable argument won't be null when the method returns the specified `bool` value. | +| [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute) | [Postcondition](#postconditions-maybenull-and-notnull) | A non-nullable parameter, field, property, or return value might be null. | +| [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute) | [Postcondition](#postconditions-maybenull-and-notnull) | A nullable parameter, field, property, or return value is never null. | +| [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A non-nullable argument might be null when the method returns the specified `bool` value. | +| [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A nullable argument isn't null when the method returns the specified `bool` value. | | [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute) | [Conditional postcondition](#conditional-post-conditions-notnullwhen-maybenullwhen-and-notnullifnotnull) | A return value, property, or argument isn't null if the argument for the specified parameter isn't null. | -| [MemberNotNull](xref:System.Diagnostics.CodeAnalysis.MemberNotNullAttribute) | [Method and property helper methods](#helper-methods-membernotnull-and-membernotnullwhen) | The listed member won't be null when the method returns. | -| [MemberNotNullWhen](xref:System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute) | [Method and property helper methods](#helper-methods-membernotnull-and-membernotnullwhen) | The listed member won't be null when the method returns the specified `bool` value. | +| [MemberNotNull](xref:System.Diagnostics.CodeAnalysis.MemberNotNullAttribute) | [Method and property helper methods](#helper-methods-membernotnull-and-membernotnullwhen) | The listed member isn't null when the method returns. | +| [MemberNotNullWhen](xref:System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute) | [Method and property helper methods](#helper-methods-membernotnull-and-membernotnullwhen) | The listed member isn't null when the method returns the specified `bool` value. | | [DoesNotReturn](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute) | [Unreachable code](#stop-nullable-analysis-when-called-method-throws) | A method or property never returns. In other words, it always throws an exception. | | [DoesNotReturnIf](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute) | [Unreachable code](#stop-nullable-analysis-when-called-method-throws) | This method or property never returns if the associated `bool` parameter has the specified value. | @@ -51,18 +51,18 @@ Consider a read/write property that never returns `null` because it has a reason :::code language="csharp" source="snippets/NullableAttributes.cs" ID="PropertyExample" ::: -When you compile the preceding code in a nullable oblivious context, everything is fine. Once you enable nullable reference types, the `ScreenName` property becomes a non-nullable reference. That's correct for the `get` accessor: it never returns `null`. Callers don't need to check the returned property for `null`. But now setting the property to `null` generates a warning. To support this type of code, you add the attribute to the property, as shown in the following code: +When you compile the preceding code in a nullable oblivious context, everything is fine. Once you enable nullable reference types, the `ScreenName` property becomes a non-nullable reference. Callers don't need to check the returned property for `null`. But now setting the property to `null` generates a warning. To support this type of code, you add the attribute to the property, as shown in the following code: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="AllowNullableProperty" ::: -You may need to add a `using` directive for to use this and other attributes discussed in this article. The attribute is applied to the property, not the `set` accessor. The `AllowNull` attribute specifies *pre-conditions*, and only applies to arguments. The `get` accessor has a return value, but no parameters. Therefore, the `AllowNull` attribute only applies to the `set` accessor. +You might need to add a `using` directive for to use this and other attributes discussed in this article. The attribute is applied to the property, not the `set` accessor. The `AllowNull` attribute specifies *pre-conditions*, and only applies to arguments. The `get` accessor has a return value, but no parameters. Therefore, the `AllowNull` attribute only applies to the `set` accessor. The preceding example demonstrates what to look for when adding the `AllowNull` attribute on an argument: 1. The general contract for that variable is that it shouldn't be `null`, so you want a non-nullable reference type. 1. There are scenarios for a caller to pass `null` as the argument, though they aren't the most common usage. -Most often you'll need this attribute for properties, or `in`, `out`, and `ref` arguments. The `AllowNull` attribute is the best choice when a variable is typically non-null, but you need to allow `null` as a precondition. +Most often you need this attribute for properties, or `in`, `out`, and `ref` arguments. The `AllowNull` attribute is the best choice when a variable is typically non-null, but you need to allow `null` as a precondition. Contrast that with scenarios for using `DisallowNull`: You use this attribute to specify that an argument of a nullable reference type shouldn't be `null`. Consider a property where `null` is the default value, but clients can only set it to a non-null value. Consider the following code: @@ -77,11 +77,11 @@ In a nullable context, the `ReviewComment` `get` accessor could return the defau 1. The variable could be `null` in core scenarios, often when first instantiated. 1. The variable shouldn't be explicitly set to `null`. -These situations are common in code that was originally *null oblivious*. It may be that object properties are set in two distinct initialization operations. It may be that some properties are set only after some asynchronous work has completed. +These situations are common in code that was originally *null oblivious*. It might be that object properties are set in two distinct initialization operations. It might be that some properties are set only after some asynchronous work completes. -The `AllowNull` and `DisallowNull` attributes enable you to specify that preconditions on variables may not match the nullable annotations on those variables. These provide more detail about the characteristics of your API. This additional information helps callers use your API correctly. Remember you specify preconditions using the following attributes: +The `AllowNull` and `DisallowNull` attributes enable you to specify that preconditions on variables might not match the nullable annotations on those variables. These annotations provide more detail about the characteristics of your API. This additional information helps callers use your API correctly. Remember you specify preconditions using the following attributes: -- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable argument may be null. +- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable argument might be null. - [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable argument should never be null. ## Postconditions: `MaybeNull` and `NotNull` @@ -92,13 +92,13 @@ Suppose you have a method with the following signature: public Customer FindCustomer(string lastName, string firstName) ``` -You've likely written a method like this to return `null` when the name sought wasn't found. The `null` clearly indicates that the record wasn't found. In this example, you'd likely change the return type from `Customer` to `Customer?`. Declaring the return value as a nullable reference type specifies the intent of this API clearly: +You likely wrote a method like this to return `null` when the name sought wasn't found. The `null` clearly indicates that the record wasn't found. In this example, you'd likely change the return type from `Customer` to `Customer?`. Declaring the return value as a nullable reference type specifies the intent of this API clearly: ```csharp public Customer? FindCustomer(string lastName, string firstName) ``` -For reasons covered under [Generics nullability](../../nullable-references.md#generics) that technique may not produce the static analysis that matches your API. You may have a generic method that follows a similar pattern: +For reasons covered under [Generics nullability](../../nullable-references.md#generics) that technique might not produce the static analysis that matches your API. You might have a generic method that follows a similar pattern: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="FindMethod" ::: @@ -106,7 +106,7 @@ The method returns `null` when the sought item isn't found. You can clarify that :::code language="csharp" source="snippets/NullableAttributes.cs" ID="FindMethodMaybeNull" ::: -The preceding code informs callers that the return value *may* actually be null. It also informs the compiler that the method may return a `null` expression even though the type is non-nullable. When you have a generic method that returns an instance of its type parameter, `T`, you can express that it never returns `null` by using the `NotNull` attribute. +The preceding code informs callers that the return value *can* actually be null. It also informs the compiler that the method can return a `null` expression even though the type is non-nullable. When you have a generic method that returns an instance of its type parameter, `T`, you can express that it never returns `null` by using the `NotNull` attribute. You can also specify that a return value or an argument isn't null even though the type is a nullable reference type. The following method is a helper method that throws if its first argument is `null`: @@ -124,8 +124,8 @@ The preceding code expresses the existing contract clearly: Callers can pass a v You specify unconditional postconditions using the following attributes: -- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value may be null. -- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value will never be null. +- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value can be null. +- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value is never null. ## Conditional post-conditions: `NotNullWhen`, `MaybeNullWhen`, and `NotNullIfNotNull` @@ -139,13 +139,13 @@ That informs the compiler that any code where the return value is `false` doesn' :::code language="csharp" source="snippets/NullableAttributes.cs" ID="NullCheckExample" ::: -The method will be annotated as shown above for .NET Core 3.0. You may have similar methods in your codebase that check the state of objects for null values. The compiler won't recognize custom null check methods, and you'll need to add the annotations yourself. When you add the attribute, the compiler's static analysis knows when the tested variable has been null checked. +The method is as shown in the previous example. You might have similar methods in your codebase that check the state of objects for null values. The compiler doesn't recognize custom null check methods, and you need to add the annotations yourself. When you add the attribute, the compiler's static analysis knows when the tested variable is null-checked. Another use for these attributes is the `Try*` pattern. The postconditions for `ref` and `out` arguments are communicated through the return value. Consider this method shown earlier (in a nullable disabled context): :::code language="csharp" source="snippets/NullableAttributes.cs" ID="TryGetExample" ::: -The preceding method follows a typical .NET idiom: the return value indicates if `message` was set to the found value or, if no message is found, to the default value. If the method returns `true`, the value of `message` isn't null; otherwise, the method sets `message` to null. +The preceding method follows a typical .NET idiom: the return value indicates if `message` was set to the sought value or, if no message is found, to the default value. If the method returns `true`, the value of `message` isn't null; otherwise, the method sets `message` to null. In a nullable enabled context, you can communicate that idiom using the `NotNullWhen` attribute. When you annotate parameters for nullable reference types, make `message` a `string?` and add an attribute: @@ -153,31 +153,31 @@ In a nullable enabled context, you can communicate that idiom using the `NotNull In the preceding example, the value of `message` is known to be not null when `TryGetMessage` returns `true`. You should annotate similar methods in your codebase in the same way: the arguments could equal `null`, and are known to be not null when the method returns `true`. -There's one final attribute you may also need. Sometimes the null state of a return value depends on the null state of one or more arguments. These methods will return a non-null value whenever certain arguments aren't `null`. To correctly annotate these methods, you use the `NotNullIfNotNull` attribute. Consider the following method: +There's one final attribute you might also need. Sometimes the null state of a return value depends on the null state of one or more arguments. These methods return a non-null value whenever certain arguments aren't `null`. To correctly annotate these methods, you use the `NotNullIfNotNull` attribute. Consider the following method: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="ExtractComponent" ::: -If the `url` argument isn't null, the output isn't `null`. Once nullable references are enabled, you need to add more annotations if your API may accept a null argument. You could annotate the return type as shown in the following code: +If the `url` argument isn't null, the output isn't `null`. Once nullable references are enabled, you need to add more annotations if your API can accept a null argument. You could annotate the return type as shown in the following code: ```csharp string? GetTopLevelDomainFromFullUrl(string? url) ``` -That also works, but will often force callers to implement extra `null` checks. The contract is that the return value would be `null` only when the argument `url` is `null`. To express that contract, you would annotate this method as shown in the following code: +That also works, but often forces callers to implement extra `null` checks. The contract is that the return value would be `null` only when the argument `url` is `null`. To express that contract, you would annotate this method as shown in the following code: :::code language="csharp" source="snippets/NullableAttributes.cs" ID="ExtractComponentIfNotNull" ::: -The previous example uses the [`nameof`](../operators/nameof.md) operator for the parameter `url`. That feature is available in C# 11. Before C# 11, you'll need to type the name of the parameter as a string. The return value and the argument have both been annotated with the `?` indicating that either could be `null`. The attribute further clarifies that the return value won't be null when the `url` argument isn't `null`. +The previous example uses the [`nameof`](../operators/nameof.md) operator for the parameter `url`. The return value and the argument have both been annotated with the `?` indicating that either could be `null`. The attribute further clarifies that the return value isn't null when the `url` argument isn't `null`. You specify conditional postconditions using these attributes: -- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable argument may be null when the method returns the specified `bool` value. -- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable argument won't be null when the method returns the specified `bool` value. +- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable argument can be null when the method returns the specified `bool` value. +- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable argument isn't null when the method returns the specified `bool` value. - [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A return value isn't null if the argument for the specified parameter isn't null. ## Helper methods: `MemberNotNull` and `MemberNotNullWhen` -These attributes specify your intent when you've refactored common code from constructors into helper methods. The C# compiler analyzes constructors and field initializers to make sure that all non-nullable reference fields have been initialized before each constructor returns. However, the C# compiler doesn't track field assignments through all helper methods. The compiler issues warning `CS8618` when fields aren't initialized directly in the constructor, but rather in a helper method. You add the to a method declaration and specify the fields that are initialized to a non-null value in the method. For example, consider the following example: +These attributes specify your intent when you refactored common code from constructors into helper methods. The C# compiler analyzes constructors and field initializers to make sure that all non-nullable reference fields are before each constructor returns. However, the C# compiler doesn't track field assignments through all helper methods. The compiler issues warning `CS8618` when fields aren't initialized directly in the constructor, but rather in a helper method. You add the to a method declaration and specify the fields that are initialized to a non-null value in the method. For example, consider the following example: :::code language="csharp" source="snippets/InitializeMembers.cs" ID="MemberNotNullExample"::: @@ -187,7 +187,7 @@ The has a `boo ## Stop nullable analysis when called method throws -Some methods, typically exception helpers or other utility methods, always exit by throwing an exception. Or, a helper may throw an exception based on the value of a Boolean argument. +Some methods, typically exception helpers, or other utility methods, always exit by throwing an exception. Or, a helper throws an exception based on the value of a Boolean argument. In the first case, you can add the attribute to the method declaration. The compiler's *null-state* analysis doesn't check any code in a method that follows a call to a method annotated with `DoesNotReturn`. Consider this method: @@ -207,12 +207,12 @@ Adding nullable reference types provides an initial vocabulary to describe your As you update libraries for a nullable context, add these attributes to guide users of your APIs to the correct usage. These attributes help you fully describe the null-state of arguments and return values. -- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable field, parameter, or property may be null. +- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable field, parameter, or property might be null. - [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable field, parameter, or property should never be null. -- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable field, parameter, property, or return value may be null. -- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable field, parameter, property, or return value will never be null. -- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable argument may be null when the method returns the specified `bool` value. -- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable argument won't be null when the method returns the specified `bool` value. +- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable field, parameter, property, or return value might be null. +- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable field, parameter, property, or return value is never null. +- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable argument might be null when the method returns the specified `bool` value. +- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable argument isn't null when the method returns the specified `bool` value. - [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A parameter, property, or return value isn't null if the argument for the specified parameter isn't null. - [DoesNotReturn](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute): A method or property never returns. In other words, it always throws an exception. - [DoesNotReturnIf](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute): This method or property never returns if the associated `bool` parameter has the specified value. diff --git a/docs/csharp/language-reference/builtin-types/default-values.md b/docs/csharp/language-reference/builtin-types/default-values.md index 4771649cda094..f0f64b5c95cd3 100644 --- a/docs/csharp/language-reference/builtin-types/default-values.md +++ b/docs/csharp/language-reference/builtin-types/default-values.md @@ -1,7 +1,7 @@ --- title: "Default values of built-in types" description: "Learn the default values of C# types such as bool, char, int, float, double, and more." -ms.date: 11/22/2024 +ms.date: 11/18/2025 helpviewer_keywords: - "default [C#]" - "parameterless constructor [C#]" @@ -47,7 +47,7 @@ Console.WriteLine(n); // output: (0, 0) At run time, if the instance represents a value type, you can use the method to invoke the parameterless constructor to obtain the default value of the type. > [!NOTE] -> A [structure type](struct.md) (which is a value type) may have an [explicit parameterless constructor](struct.md#struct-initialization-and-default-values) that may produce a non-default value of the type. Thus, we recommend using the `default` operator or the `default` literal to produce the default value of a type. +> A [structure type](struct.md) (which is a value type) can have an [explicit parameterless constructor](struct.md#struct-initialization-and-default-values) that might produce a non-default value of the type. Thus, we recommend using the `default` operator or the `default` literal to produce the default value of a type. ## C# language specification @@ -56,7 +56,7 @@ For more information, see the following sections of the [C# language specificati - [Default values](~/_csharpstandard/standard/variables.md#93-default-values) - [Default constructors](~/_csharpstandard/standard/types.md#833-default-constructors) - [Parameterless struct constructors](~/_csharplang/proposals/csharp-10.0/parameterless-struct-constructors.md) -- [C# 11 - Auto default structs](~/_csharplang/proposals/csharp-11.0/auto-default-structs.md) +- [Auto default structs](~/_csharplang/proposals/csharp-11.0/auto-default-structs.md) ## See also diff --git a/docs/csharp/language-reference/builtin-types/integral-numeric-types.md b/docs/csharp/language-reference/builtin-types/integral-numeric-types.md index 3a6d33c148519..78e0076a5617f 100644 --- a/docs/csharp/language-reference/builtin-types/integral-numeric-types.md +++ b/docs/csharp/language-reference/builtin-types/integral-numeric-types.md @@ -2,7 +2,7 @@ title: "Integral numeric types" titleSuffix: "" description: "Learn the range, storage size, and uses for each of the integral numeric types." -ms.date: 06/17/2022 +ms.date: 11/18/2025 f1_keywords: - "byte_CSharpKeyword" - "sbyte_CSharpKeyword" @@ -32,7 +32,7 @@ helpviewer_keywords: --- # Integral numeric types (C# reference) -The *integral numeric types* represent integer numbers. All integral numeric types are [value types](value-types.md). They're also [simple types](value-types.md#built-in-value-types) and can be initialized with [literals](#integer-literals). All integral numeric types support [arithmetic](../operators/arithmetic-operators.md), [bitwise logical](../operators/bitwise-and-shift-operators.md), [comparison](../operators/comparison-operators.md), and [equality](../operators/equality-operators.md) operators. +The *integral numeric types* represent integer numbers. All integral numeric types are [value types](value-types.md). The integral types are [simple types](value-types.md#built-in-value-types) and can be initialized with [literals](#integer-literals). All integral numeric types support [arithmetic](../operators/arithmetic-operators.md), [bitwise logical](../operators/bitwise-and-shift-operators.md), [comparison](../operators/comparison-operators.md), and [equality](../operators/equality-operators.md) operators. ## Characteristics of the integral types @@ -58,9 +58,9 @@ int a = 123; System.Int32 b = 123; ``` -The `nint` and `nuint` types in the last two rows of the table are native-sized integers. You can use the `nint` and `nuint` contextual keywords to define *native-sized integers*. These are 32-bit integers when running in a 32-bit process, or 64-bit integers when running in a 64-bit process. They can be used for interop scenarios, low-level libraries, and to optimize performance in scenarios where integer math is used extensively. +The `nint` and `nuint` types in the last two rows of the table are native-sized integers. You can use the `nint` and `nuint` contextual keywords to define *native-sized integers*. Native-sized integers are 32-bit integers when running in a 32-bit process, or 64-bit integers when running in a 64-bit process. They can be used for interop scenarios, low-level libraries, and to optimize performance in scenarios where integer math is used extensively. -The native-sized integer types are represented internally as the .NET types and . Starting in C# 11, the `nint` and `nuint` types are aliases for the underlying types. +The native-sized integer types are represented internally as the .NET types and . The `nint` and `nuint` types are aliases for the underlying types. The default value of each integral type is zero, `0`. @@ -86,24 +86,24 @@ var binaryLiteral = 0b_0010_1010; The preceding example also shows the use of `_` as a *digit separator*. You can use the digit separator with all kinds of numeric literals. -The type of an integer literal is determined by its suffix as follows: +The suffix determines the type of an integer literal as follows: - If the literal has no suffix, its type is the first of the following types in which its value can be represented: `int`, `uint`, `long`, `ulong`. > [!NOTE] - > Literals are interpreted as positive values. For example, the literal `0xFF_FF_FF_FF` represents the number `4294967295` of the `uint` type, though it has the same bit representation as the number `-1` of the `int` type. If you need a value of a certain type, cast a literal to that type. Use the `unchecked` operator, if a literal value cannot be represented in the target type. For example, `unchecked((int)0xFF_FF_FF_FF)` produces `-1`. + > Literals are interpreted as positive values. For example, the literal `0xFF_FF_FF_FF` represents the number `4294967295` of the `uint` type, though it has the same bit representation as the number `-1` of the `int` type. If you need a value of a certain type, cast a literal to that type. Use the `unchecked` operator, if a literal value can't be represented in the target type. For example, `unchecked((int)0xFF_FF_FF_FF)` produces `-1`. -- If the literal is suffixed by `U` or `u`, its type is the first of the following types in which its value can be represented: `uint`, `ulong`. -- If the literal is suffixed by `L` or `l`, its type is the first of the following types in which its value can be represented: `long`, `ulong`. +- If the literal includes the `U` or `u` suffix, its type is the first of the following types in which its value can be represented: `uint`, `ulong`. +- If the literal includes the `L` or `l` suffix, its type is the first of the following types in which its value can be represented: `long`, `ulong`. > [!NOTE] - > You can use the lowercase letter `l` as a suffix. However, this generates a compiler warning because the letter `l` can be confused with the digit `1`. Use `L` for clarity. + > You can use the lowercase letter `l` as a suffix. However, `l` generates a compiler warning because the letter `l` can be confused with the digit `1`. Use `L` for clarity. -- If the literal is suffixed by `UL`, `Ul`, `uL`, `ul`, `LU`, `Lu`, `lU`, or `lu`, its type is `ulong`. +- If the literal includes one of the `UL`, `Ul`, `uL`, `ul`, `LU`, `Lu`, `lU`, or `lu` suffixes, its type is `ulong`. If the value represented by an integer literal exceeds , a compiler error [CS1021](../../misc/cs1021.md) occurs. -If the determined type of an integer literal is `int` and the value represented by the literal is within the range of the destination type, the value can be implicitly converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, `nint` or `nuint`: +If the determined type of an integer literal is `int` and the value represented by the literal is within the range of the destination type, the value can be implicitly converted to `sbyte`, `byte`, `short`, `ushort`, `uint`, `ulong`, `nint`, or `nuint`: ```csharp byte a = 17; @@ -125,7 +125,7 @@ You can convert any integral numeric type to any other integral numeric type. If ## Native sized integers -Native sized integer types have special behavior because the storage is determined by the natural integer size on the target machine. +Native sized integer types have special behavior because the storage matches the natural integer size on the target machine. - To get the size of a native-sized integer at run time, you can use `sizeof()`. However, the code must be compiled in an unsafe context. For example: @@ -136,7 +136,7 @@ Native sized integer types have special behavior because the storage is determin :::code language="csharp" source="snippets/shared/NativeIntegerTypes.cs" id="MinMax"::: -- While the full range of `nint` and `nuint` may be larger, compile-time constants are restricted to a 32-bit range: +- While the full range of `nint` and `nuint` can be larger, compile-time constants are restricted to a 32-bit range: - For `nint`: to . - For `nuint`: to . - The compiler provides implicit and explicit conversions to other numeric types. For more information, see [Built-in numeric conversions](numeric-conversions.md). @@ -154,7 +154,7 @@ For more information, see the following sections of the [C# language specificati - [Integral types](~/_csharpstandard/standard/types.md#836-integral-types) - [Integer literals](~/_csharpstandard/standard/lexical-structure.md#6453-integer-literals) - [Native sized integral types](~/_csharplang/proposals/csharp-9.0/native-integers.md) -- [C# 11 - Numeric `IntPtr` and `UIntPtr`](~/_csharplang/proposals/csharp-11.0/numeric-intptr.md) +- [Numeric `IntPtr` and `UIntPtr`](~/_csharplang/proposals/csharp-11.0/numeric-intptr.md) ## See also diff --git a/docs/csharp/language-reference/builtin-types/ref-struct.md b/docs/csharp/language-reference/builtin-types/ref-struct.md index 47968683e9d17..6980dca043b51 100644 --- a/docs/csharp/language-reference/builtin-types/ref-struct.md +++ b/docs/csharp/language-reference/builtin-types/ref-struct.md @@ -1,7 +1,7 @@ --- title: "ref struct types" description: Learn about the ref struct type in C# -ms.date: 01/27/2025 +ms.date: 11/18/2025 --- # `ref` structure types (C# reference) @@ -28,7 +28,7 @@ In .NET, examples of a `ref struct` are [!IMPORTANT] -> A `ref struct` that implements an interface includes the potential for later source-breaking and binary-breaking changes. The break occurs if a `ref struct` implements an interface defined in another assembly, and that assembly provides an update which adds default members to that interface. +> A `ref struct` that implements an interface includes the potential for later source-breaking and binary-breaking changes. The break occurs if a `ref struct` implements an interface defined in another assembly, and that assembly provides an update that adds default members to that interface. > > The source-break happens when you recompile the `ref struct`: It must implement the new member, even though there's a default implementation. > diff --git a/docs/csharp/language-reference/builtin-types/reference-types.md b/docs/csharp/language-reference/builtin-types/reference-types.md index f13a34454034b..3f2dd12793eb0 100644 --- a/docs/csharp/language-reference/builtin-types/reference-types.md +++ b/docs/csharp/language-reference/builtin-types/reference-types.md @@ -1,7 +1,7 @@ --- title: "Built-in reference types" description: "Learn about reference types that have C# keywords you can use to declare them." -ms.date: 10/07/2025 +ms.date: 11/18/2025 f1_keywords: - "object_CSharpKeyword" - "object" @@ -85,7 +85,7 @@ for (int i = 0; i < str.Length; i++) String literals are of type `string` and can be written in three forms, raw, quoted, and verbatim. -*Raw string literals* are available beginning in C# 11. Raw string literals can contain arbitrary text without requiring escape sequences. Raw string literals can include whitespace and new lines, embedded quotes, and other special characters. Raw string literals are enclosed in a minimum of three double quotation marks ("""): +*Raw string literals* contain arbitrary text without requiring escape sequences. Raw string literals can include whitespace and new lines, embedded quotes, and other special characters. Raw string literals are enclosed in a minimum of three double quotation marks ("""): ```csharp """ @@ -186,7 +186,7 @@ To include a double quotation mark in an @-quoted string, double it: ### UTF-8 string literals -Strings in .NET are stored using UTF-16 encoding. UTF-8 is the standard for Web protocols and other important libraries. Beginning in C# 11, you can add the `u8` suffix to a string literal to specify UTF-8 encoding. UTF-8 literals are stored as `ReadOnlySpan` objects. The natural type of a UTF-8 string literal is `ReadOnlySpan`. Using a UTF-8 string literal creates a more clear declaration than declaring the equivalent , as shown in the following code: +Strings in .NET are stored using UTF-16 encoding. UTF-8 is the standard for Web protocols and other important libraries. You can add the `u8` suffix to a string literal to specify UTF-8 encoding. UTF-8 literals are stored as `ReadOnlySpan` objects. The natural type of a UTF-8 string literal is `ReadOnlySpan`. Using a UTF-8 string literal creates a more clear declaration than declaring the equivalent , as shown in the following code: ```csharp ReadOnlySpan AuthWithTrailingSpace = new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 }; @@ -281,8 +281,8 @@ For more information, see the following sections of the [C# language specificati - [§8.2.4 The dynamic type](~/_csharpstandard/standard/types.md#824-the-dynamic-type) - [§8.2.5 The string type](~/_csharpstandard/standard/types.md#825-the-string-type) - [§8.2.8 Delegate types](~/_csharpstandard/standard/types.md#828-delegate-types) -- [C# 11 - Raw string literals](~/_csharplang/proposals/csharp-11.0/raw-string-literal.md) -- [C# 11 - Raw string literals](~/_csharplang/proposals/csharp-11.0/utf8-string-literals.md) +- [Raw string literals](~/_csharplang/proposals/csharp-11.0/raw-string-literal.md) +- [UTF-8 string literals](~/_csharplang/proposals/csharp-11.0/utf8-string-literals.md) ### See also diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index 3c2f4b448cc29..7fadfdfd79a3f 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -1,7 +1,7 @@ --- title: "Structure types" description: Learn about the struct type in C# -ms.date: 11/22/2024 +ms.date: 11/18/2025 f1_keywords: - "struct_CSharpKeyword" helpviewer_keywords: @@ -110,11 +110,11 @@ But it can be any reference type, or any value type: You can use inline arrays with almost any C# data structure. -Inline arrays are an advanced language feature. They're intended for high-performance scenarios where an inline, contiguous block of elements is faster than other alternative data structures. You can learn more about inline arrays from the [feature speclet](~/_csharplang/proposals/csharp-12.0/inline-arrays.md). +Inline arrays are an advanced language feature. They're intended for high-performance scenarios where an inline, contiguous block of elements is faster than other alternative data structures. You can learn more about inline arrays from the [feature spec](~/_csharplang/proposals/csharp-12.0/inline-arrays.md). ## Struct initialization and default values -A variable of a `struct` type directly contains the data for that `struct`. That creates a distinction between an uninitialized `struct`, which has its default value and an initialized `struct`, which stores values set by constructing it. For example consider the following code: +A variable of a `struct` type directly contains the data for that `struct`. That creates a distinction between an uninitialized `struct`, which has its default value and an initialized `struct`, which stores values set by constructing it. For example, consider the following code: :::code language="csharp" source="snippets/shared/StructType.cs" id="ParameterlessConstructor"::: @@ -132,7 +132,7 @@ All of a struct's member fields must be *definitely assigned* when created becau - You can add *field initializers* to any field or auto implemented property. - You can initialize any fields, or auto properties, in the body of the constructor. -Beginning with C# 11, if you don't initialize all fields in a struct, the compiler adds code to the constructor that initializes those fields to the default value. A struct assigned to its `default` value is initialized to the 0-bit pattern. A struct initialized with `new` is initialized to the 0-bit pattern, followed by executing any field initializers and a constructor. +If you don't initialize all fields in a struct, the compiler adds code to the constructor that initializes those fields to the default value. A struct assigned to its `default` value is initialized to the 0-bit pattern. A struct initialized with `new` is initialized to the 0-bit pattern, followed by executing any field initializers and a constructor. :::code language="csharp" source="snippets/shared/StructType.cs" id="FieldInitializer"::: @@ -152,7 +152,7 @@ Structs have most of the capabilities of a [class](../keywords/class.md) type. T - A structure type can't inherit from other class or structure type and it can't be the base of a class. However, a structure type can implement [interfaces](../keywords/interface.md). - You can't declare a [finalizer](../../programming-guide/classes-and-structs/finalizers.md) within a structure type. -- Before C# 11, a constructor of a structure type must initialize all instance fields of the type. +- A constructor of a structure type must initialize all instance fields of the type. ## Passing structure-type variables by reference diff --git a/docs/csharp/language-reference/keywords/file.md b/docs/csharp/language-reference/keywords/file.md index fcf926adc3812..702b3248d3877 100644 --- a/docs/csharp/language-reference/keywords/file.md +++ b/docs/csharp/language-reference/keywords/file.md @@ -1,7 +1,7 @@ --- -description: "The file modifier: Declare types whose visibility is the file in which it's declared" +description: "The file modifier: Declare types whose visibility is the containing file" title: "The file keyword" -ms.date: 12/10/2024 +ms.date: 11/18/2025 f1_keywords: - "file_CSharpKeyword" helpviewer_keywords: @@ -9,9 +9,7 @@ helpviewer_keywords: --- # The file modifier -Beginning with C# 11, the `file` contextual keyword is a type modifier. - -The `file` modifier restricts a top-level type's visibility to the file in which it's declared. The `file` modifier is most often applied to types written by a source generator. File-local types provide source generators with a convenient way to avoid name collisions among generated types. The `file` modifier declares a file-local type, as in this example: +The `file` modifier restricts a top-level type's visibility to the file containing its declaration. The `file` modifier is most often applied to types written by a source generator. File-local types provide source generators with a convenient way to avoid name collisions among generated types. The `file` modifier declares a file-local type, as in this example: ```csharp file class HiddenWidget @@ -20,9 +18,9 @@ file class HiddenWidget } ``` -Any types nested within a file-local type are also only visible within the file in which it's declared. Other types in an assembly can use the same name as a file-local type. Because the file-local type is visible only in the file where it's declared, these types don't create a naming collision. +Any types nested within a file-local type are also only visible within the file containing its declaration. Other types in an assembly can use the same name as a file-local type. Because the file-local type is visible only in the file containing its declaration, these types don't create a naming collision. -A file-local type can't be the return type or parameter type of any member declared in a non file-local type. A file-local type can't be a field member of a non-file-local. However, a more visible type can implicitly implement a file-local interface type. The type can also [explicitly implement](../../programming-guide/interfaces/explicit-interface-implementation.md) a file-local interface but explicit implementations can only be used within the same file. +A file-local type can't be the return type or parameter type of any member declared in a non-file-local type. A file-local type can't be a field member of a non-file-local. However, a more visible type can implicitly implement a file-local interface type. The type can also [explicitly implement](../../programming-guide/interfaces/explicit-interface-implementation.md) a file-local interface but explicit implementations can only be used within the same file. The following example shows a public type that uses a file-local type to provide a worker method. In addition, the public type implements a file-local interface implicitly: @@ -36,7 +34,7 @@ Member lookup prefers a file-local type declared in the same file over a non-fil ## C# language specification -For more information, see [Declared accessibility](~/_csharpstandard/standard/basic-concepts.md#752-declared-accessibility) in the [C# Language Specification](~/_csharpstandard/standard/README.md), and the [C# 11 - File local types](~/_csharplang/proposals/csharp-11.0/file-local-types.md) feature specification. +For more information, see [Declared accessibility](~/_csharpstandard/standard/basic-concepts.md#752-declared-accessibility) in the [C# Language Specification](~/_csharpstandard/standard/README.md), and the [File local types](~/_csharplang/proposals/csharp-11.0/file-local-types.md) feature specification. ## See also diff --git a/docs/csharp/language-reference/keywords/interface.md b/docs/csharp/language-reference/keywords/interface.md index 9b43f13c89d31..c2903428e843a 100644 --- a/docs/csharp/language-reference/keywords/interface.md +++ b/docs/csharp/language-reference/keywords/interface.md @@ -1,7 +1,7 @@ --- description: "Use the `interface` keyword to define contracts that any implementing type must support. Interfaces provide the means to create common behavior among a set of unrelated types." title: "interface keyword" -ms.date: 07/26/2024 +ms.date: 11/18/2024 f1_keywords: - "interface_CSharpKeyword" helpviewer_keywords: @@ -9,11 +9,11 @@ helpviewer_keywords: --- # :::no-loc text="interface"::: (C# Reference) -An interface defines a contract. Any [`class`](class.md), [`record`](../builtin-types/record.md) or [`struct`](../builtin-types/struct.md) that implements that contract must provide an implementation of the members defined in the interface. +An interface defines a contract. Any [`class`](class.md), [`record`](../builtin-types/record.md), or [`struct`](../builtin-types/struct.md) that implements that contract must provide an implementation of the members defined in the interface. An interface can define a [default implementation](#default-interface-members) for a member. It can also define [`static`](static.md) members to provide a single implementation for common functionality. -Beginning with C# 11, an interface can define `static abstract` or `static virtual` members to declare that an implementing type must provide the declared members. Typically, `static virtual` methods declare that an implementation must define a set of [overloaded operators](../operators/operator-overloading.md). +An interface can define `static abstract` or `static virtual` members to declare that an implementing type must provide the declared members. Typically, `static virtual` methods declare that an implementation must define a set of [overloaded operators](../operators/operator-overloading.md). In the following example, class `ImplementationClass` must implement a method named `SampleMethod` that has no parameters and returns `void`. @@ -23,9 +23,9 @@ For more information and examples, see [Interfaces](../../fundamentals/types/int ## Access modifiers -An interface can be a member of a namespace or a class. A top-level interface, one declared in a namespace but not nested inside another type, can be declared `public` or `internal`. The default is `internal`. Nested interface declarations, those declared inside another type, can be declared using any access modifier. +An interface can be a member of a namespace or a class. A top-level interface, one declared in a namespace but not nested inside another type, can be declared `public` or `internal`. The default is `internal`. Nested interface declarations, declared inside another type, can be declared using any access modifier. -Interface members *without* an implementation (abstract members) are implicitly `public` and cannot have any other access modifier. Interface members *with* a default implementation are `private` by default if no access modifier is specified, but can be declared with any access modifier (`public`, `private`, `protected`, or `internal`). +Interface members *without* an implementation (abstract members) are implicitly `public` and can't have any other access modifier. Interface members *with* a default implementation are `private` by default if no access modifier is specified, but can be declared with any access modifier (`public`, `private`, `protected`, or `internal`). ## Interface members @@ -51,10 +51,10 @@ Member declarations typically don't contain a body, however, an interface member ## Static abstract and virtual members -Beginning with C# 11, an interface can declare `static abstract` and `static virtual` members for all member types except fields. Interfaces can declare that implementing types must define operators or other static members. This feature enables generic algorithms to specify number-like behavior. You can see examples in the numeric types in the .NET runtime, such as . These interfaces define common mathematical operators that are implemented by many numeric types. The compiler must resolve calls to `static virtual` and `static abstract` methods at compile time. The `static virtual` and `static abstract` methods declared in interfaces don't have a runtime dispatch mechanism analogous to `virtual` or `abstract` methods declared in classes. Instead, the compiler uses type information available at compile time. Therefore, `static virtual` methods are almost exclusively declared in [generic interfaces](../../programming-guide/generics/generic-interfaces.md). Furthermore, most interfaces that declare `static virtual` or `static abstract` methods declare that one of the type parameters must [implement the declared interface](../../programming-guide/generics/constraints-on-type-parameters.md#type-arguments-implement-declared-interface). For example, the `INumber` interface declares that `T` must implement `INumber`. The compiler uses the type argument to resolve calls to the methods and operators declared in the interface declaration. For example, the `int` type implements `INumber`. When the type parameter `T` denotes the type argument `int`, the `static` members declared on `int` are invoked. Alternatively, when `double` is the type argument, the `static` members declared on the `double` type are invoked. +An interface can declare `static abstract` and `static virtual` members for all member types except fields. Interfaces can declare that implementing types must define operators or other static members. This feature enables generic algorithms to specify number-like behavior. You can see examples in the numeric types in the .NET runtime, such as . These interfaces define common mathematical operators implemented by many numeric types. The compiler must resolve calls to `static virtual` and `static abstract` methods at compile time. The `static virtual` and `static abstract` methods declared in interfaces don't have a runtime dispatch mechanism analogous to `virtual` or `abstract` methods declared in classes. Instead, the compiler uses type information available at compile time. Therefore, `static virtual` methods are almost exclusively declared in [generic interfaces](../../programming-guide/generics/generic-interfaces.md). Furthermore, most interfaces that declare `static virtual` or `static abstract` methods declare that one of the type parameters must [implement the declared interface](../../programming-guide/generics/constraints-on-type-parameters.md#type-arguments-implement-declared-interface). For example, the `INumber` interface declares that `T` must implement `INumber`. The compiler uses the type argument to resolve calls to the methods and operators declared in the interface declaration. For example, the `int` type implements `INumber`. When the type parameter `T` denotes the type argument `int`, the `static` members declared on `int` are invoked. Alternatively, when `double` is the type argument, the `static` members declared on the `double` type are invoked. > [!IMPORTANT] -> Method dispatch for `static abstract` and `static virtual` methods declared in interfaces is resolved using the compile time type of an expression. If the runtime type of an expression is derived from a different compile time type, the static methods on the base (compile time) type will be called. +> Method dispatch for `static abstract` and `static virtual` methods declared in interfaces is resolved using the compile time type of an expression. If the runtime type of an expression is derived from a different compile time type, the static methods on the base (compile time) type are called. You can try this feature by working with the tutorial on [static abstract members in interfaces](../../whats-new/tutorials/static-virtual-interface-members.md). @@ -69,7 +69,7 @@ public interface INamed } ``` -An interface can inherit from one or more base interfaces. When an interface inherits from another interface, a type implementing the derived interface must implement all the members in the base interfaces as well as those declared in the derived interface, as shown in the following code: +An interface can inherit from one or more base interfaces. When an interface inherits from another interface, a type implementing the derived interface must implement all the members in the base interfaces in addition to those members declared in the derived interface, as shown in the following code: :::code language="csharp" source="./snippets/DefineTypes.cs" id="SnippetDerivedInterfaces"::: @@ -89,7 +89,7 @@ The following example demonstrates interface implementation. In this example, th ## C# language specification -For more information, see the [Interfaces](~/_csharpstandard/standard/interfaces.md) section of the [C# language specification](~/_csharpstandard/standard/README.md) and the feature spec for [C# 11 - static abstract members in interfaces](~/_csharplang/proposals/csharp-11.0/static-abstracts-in-interfaces.md). +For more information, see the [Interfaces](~/_csharpstandard/standard/interfaces.md) section of the [C# language specification](~/_csharpstandard/standard/README.md) and the feature spec for [static abstract members in interfaces](~/_csharplang/proposals/csharp-11.0/static-abstracts-in-interfaces.md). ## See also diff --git a/docs/csharp/language-reference/operators/addition-operator.md b/docs/csharp/language-reference/operators/addition-operator.md index 9bd1eb56cb85a..af7c6f47258d2 100644 --- a/docs/csharp/language-reference/operators/addition-operator.md +++ b/docs/csharp/language-reference/operators/addition-operator.md @@ -1,7 +1,7 @@ --- title: "Addition operators - + and +=" description: "The C# addition operators (`+`, and `+=`) work with operands of numeric, string, or delegate types." -ms.date: 06/11/2025 +ms.date: 11/18/2025 f1_keywords: - "+_CSharpKeyword" - "+=_CSharpKeyword" @@ -32,7 +32,7 @@ When one or both operands are of type [string](../builtin-types/reference-types. You can use string interpolation to initialize a constant string when all the expressions used for placeholders are also constant strings. -Beginning with C# 11, the `+` operator performs string concatenation for UTF-8 literal strings. This operator concatenates two `ReadOnlySpan` objects. +The `+` operator performs string concatenation for UTF-8 literal strings. This operator concatenates two `ReadOnlySpan` objects. ## Delegate combination diff --git a/docs/csharp/language-reference/operators/arithmetic-operators.md b/docs/csharp/language-reference/operators/arithmetic-operators.md index 6e59c88f175e1..df308371296ee 100644 --- a/docs/csharp/language-reference/operators/arithmetic-operators.md +++ b/docs/csharp/language-reference/operators/arithmetic-operators.md @@ -1,7 +1,7 @@ --- title: "Arithmetic operators" description: "Learn about C# operators that perform multiplication, division, remainder, addition, and subtraction operations with numeric types." -ms.date: 06/11/2025 +ms.date: 11/18/2025 author: pkulikov f1_keywords: - "++_CSharpKeyword" @@ -133,7 +133,7 @@ Use the method to comp For the `float` and `double` operands, the result of `x % y` for the finite `x` and `y` is the value `z` such that - The sign of `z`, if non-zero, is the same as the sign of `x`. -- The absolute value of `z` is the value produced by `|x| - n * |y|` where `n` is the largest possible integer that is less than or equal to `|x| / |y|` and `|x|` and `|y|` are the absolute values of `x` and `y`, respectively. +- The absolute value of `z` is the value produced by `|x| - n * |y|` where `n` is the largest possible integer that's less than or equal to `|x| / |y|` and `|x|` and `|y|` are the absolute values of `x` and `y`, respectively. > [!NOTE] > This method of computing the remainder is analogous to the method used for integer operands, but different from the IEEE 754 specification. If you need the remainder operation that complies with the IEEE 754 specification, use the method. @@ -251,13 +251,13 @@ A user-defined type can [overload](operator-overloading.md) the unary (`++`, `-- ### User-defined checked operators -Beginning with C# 11, when you overload an arithmetic operator, you can use the `checked` keyword to define the *checked* version of that operator. The following example shows how to do that: +When you overload an arithmetic operator, you can use the `checked` keyword to define the *checked* version of that operator. The following example shows how to do that: :::code language="csharp" source="snippets/shared/ArithmeticOperators.cs" id="CheckedOperator"::: -When you define a checked operator, you must also define the corresponding operator without the `checked` modifier. The checked operator is called in a [checked context](../statements/checked-and-unchecked.md); the operator without the `checked` modifier is called in an [unchecked context](../statements/checked-and-unchecked.md). If you only provide the operator without the `checked` modifier, it's called in both a `checked` and `unchecked` context. +When you define a checked operator, you must also define the corresponding operator without the `checked` modifier. The checked operator is called in a [checked context](../statements/checked-and-unchecked.md); the operator without the `checked` modifier is called in an [unchecked context](../statements/checked-and-unchecked.md). -When you define both versions of an operator, it's expected that their behavior differs only when the result of an operation is too large to represent in the result type as follows: +When you define both versions of an operator, their behavior differs only when the result of an operation is too large to represent in the result type as follows: - A checked operator throws an . - An operator without the `checked` modifier returns an instance representing a *truncated* result. @@ -272,7 +272,7 @@ You can use the `checked` modifier only when you overload any of the following o - [Explicit conversion operators](user-defined-conversion-operators.md) > [!NOTE] -> The overflow-checking context within the body of a checked operator isn't affected by the presence of the `checked` modifier. The default context is defined by the value of the [**CheckForOverflowUnderflow**](../compiler-options/language.md#checkforoverflowunderflow) compiler option. Use the [`checked` and `unchecked` statements](../statements/checked-and-unchecked.md) to explicitly specify the overflow-checking context, as the example at the beginning of this section demonstrates. +> The presence of the `checked` modifier doesn't affect the overflow-checking context within its body. The default context is defined by the value of the [**CheckForOverflowUnderflow**](../compiler-options/language.md#checkforoverflowunderflow) compiler option. Use the [`checked` and `unchecked` statements](../statements/checked-and-unchecked.md) to explicitly specify the overflow-checking context, as the example at the beginning of this section demonstrates. ## C# language specification diff --git a/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md b/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md index e6b9303a024a7..1f593ab39413c 100644 --- a/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md +++ b/docs/csharp/language-reference/operators/bitwise-and-shift-operators.md @@ -1,7 +1,7 @@ --- title: "Bitwise and shift operators - perform boolean (AND, NOT, OR, XOR) and shift operations on individual bits in integral types" description: "Learn about C# operators that perform bitwise logical (AND - `&`, NOT - `~`, OR - `|`, XOR - `^`) or shift operations(`<<`, and `>>`) with operands of integral types. " -ms.date: 06/11/2025 +ms.date: 11/18/2025 author: pkulikov f1_keywords: - "~_CSharpKeyword" @@ -89,11 +89,11 @@ The high-order empty bit positions are set based on the type of the left-hand op :::code language="csharp" interactive="try-dotnet-method" source="snippets/shared/BitwiseAndShiftOperators.cs" id="LogicalRightShift"::: > [!NOTE] -> Use the [unsigned right-shift operator](#unsigned-right-shift-operator-) to perform a *logical* shift on operands of signed integer types. The logical shift is preferred to casting a left-hand operand to an unsigned type and then casting the result of a shift operation back to a signed type. +> Use the [unsigned right-shift operator](#unsigned-right-shift-operator-) to perform a *logical* shift on operands of signed integer types. The logical shift is preferred. Avoid casting the left-hand operand to an unsigned type and then casting the result of a shift operation back to a signed type. ## Unsigned right-shift operator >>> -Available in C# 11 and later, the `>>>` operator shifts its left-hand operand right by the number of bits defined by its right-hand operand. For information about how the right-hand operand defines the shift count, see the [Shift count of the shift operators](#shift-count-of-the-shift-operators) section. +The `>>>` operator shifts its left-hand operand right by the number of bits defined by its right-hand operand. For information about how the right-hand operand defines the shift count, see the [Shift count of the shift operators](#shift-count-of-the-shift-operators) section. The `>>>` operator always performs a *logical* shift. That is, the high-order empty bit positions are always set to zero, regardless of the type of the left-hand operand. The [`>>` operator](#right-shift-operator-) performs an *arithmetic* shift (that is, the value of the most significant bit is propagated to the high-order empty bit positions) if the left-hand operand is of a signed type. The following example demonstrates the difference between `>>` and `>>>` operators for a negative left-hand operand: @@ -188,7 +188,7 @@ You typically use bitwise logical operators with an enumeration type that is def A user-defined type can [overload](operator-overloading.md) the `~`, `<<`, `>>`, `>>>`, `&`, `|`, and `^` operators. When a binary operator is overloaded, the corresponding compound assignment operator is also implicitly overloaded. Beginning with C# 14, a user-defined type can explicitly overload the compound assignment operators to provide a more efficient implementation. Typically, a type overloads these operators because the value can be updated in place, rather than allocating a new instance to store the result of the binary operation. If a type doesn't provide an explicit overload, the compiler generates the implicit overload. -If a user-defined type `T` overloads the `<<`, `>>`, or `>>>` operator, the type of the left-hand operand must be `T`. In C# 10 and earlier, the type of the right-hand operand must be `int`; beginning with C# 11, the type of the right-hand operand of an overloaded shift operator can be any. +If a user-defined type `T` overloads the `<<`, `>>`, or `>>>` operator, the type of the left-hand operand must be `T`. In C# 10 and earlier, the type of the right-hand operand must be `int`; the type of the right-hand operand of an overloaded shift operator can be any. ## C# language specification @@ -199,8 +199,8 @@ For more information, see the following sections of the [C# language specificati - [Logical operators](~/_csharpstandard/standard/expressions.md#1215-logical-operators) - [Compound assignment](~/_csharpstandard/standard/expressions.md#12234-compound-assignment) - [Numeric promotions](~/_csharpstandard/standard/expressions.md#1247-numeric-promotions) -- [C# 11 - Relaxed shift requirements](~/_csharplang/proposals/csharp-11.0/relaxing_shift_operator_requirements.md) -- [C# 11 - Logical right-shift operator](~/_csharplang/proposals/csharp-11.0/unsigned-right-shift-operator.md) +- [Relaxed shift requirements](~/_csharplang/proposals/csharp-11.0/relaxing_shift_operator_requirements.md) +- [Logical right-shift operator](~/_csharplang/proposals/csharp-11.0/unsigned-right-shift-operator.md) - [User defined compound assignment](~/_csharplang/proposals/csharp-14.0/user-defined-compound-assignment.md) ## See also diff --git a/docs/csharp/language-reference/operators/delegate-operator.md b/docs/csharp/language-reference/operators/delegate-operator.md index f940870824729..02721ad088e78 100644 --- a/docs/csharp/language-reference/operators/delegate-operator.md +++ b/docs/csharp/language-reference/operators/delegate-operator.md @@ -1,7 +1,7 @@ --- title: "delegate operator - Create an anonymous method that can be converted to a delegate type." description: "The C# delegate operator that is used to create anonymous methods. These types can be used for `Func<>` and `Action<>` parameters in many .NET APIs." -ms.date: 11/29/2022 +ms.date: 11/18/2022 helpviewer_keywords: - "delegate [C#]" - "anonymous method [C#]" @@ -23,7 +23,7 @@ When you use the `delegate` operator, you might omit the parameter list. If you [!code-csharp-interactive[no parameter list](snippets/shared/DelegateOperator.cs#WithoutParameterList)] -That's the only functionality of anonymous methods that isn't supported by lambda expressions. In all other cases, a lambda expression is a preferred way to write inline code. You can use [discards](../../fundamentals/functional/discards.md) to specify two or more input parameters of an anonymous method that aren't used by the method: +That's the only functionality of anonymous methods not supported by lambda expressions. In all other cases, a lambda expression is a preferred way to write inline code. You can use [discards](../../fundamentals/functional/discards.md) to specify two or more input parameters of an anonymous method that aren't used by the method: :::code language="csharp" source="snippets/shared/DelegateOperator.cs" id="SnippetDiscards" ::: @@ -37,19 +37,19 @@ A static anonymous method can't capture local variables or instance state from e You also use the `delegate` keyword to declare a [delegate type](../builtin-types/reference-types.md#the-delegate-type). -Beginning with C# 11, the compiler may cache the delegate object created from a method group. Consider the following method: +The compiler can cache the delegate object created from a method group. Consider the following method: ```csharp static void StaticFunction() { } ``` -When you assign the method group to a delegate, the compiler will cache the delegate: +When you assign the method group to a delegate, the compiler caches the delegate: ```csharp Action a = StaticFunction; ``` -Before C# 11, you'd need to use a lambda expression to reuse a single delegate object: +You'd need to use a lambda expression to reuse a single delegate object: ```csharp Action a = () => StaticFunction(); diff --git a/docs/csharp/language-reference/operators/is.md b/docs/csharp/language-reference/operators/is.md index b375dc60afe87..a8ad38d9e9e95 100644 --- a/docs/csharp/language-reference/operators/is.md +++ b/docs/csharp/language-reference/operators/is.md @@ -1,7 +1,7 @@ --- title: "The `is` operator - Match an expression against a type or constant pattern" description: "Learn about the C# `is` operator that matches an expression against a pattern. The `is` operator returns true when the expression matches the pattern." -ms.date: 02/18/2025 +ms.date: 11/18/2025 f1_keywords: - "is_CSharpKeyword" - "is" @@ -34,7 +34,7 @@ The `is` operator can be useful in the following scenarios: :::code language="csharp" source="snippets/shared/IsOperator.cs" id="NonNullCheck"::: -- Beginning with C# 11, you can use [list patterns](patterns.md#list-patterns) to match elements of a list or array. The following code checks arrays for integer values in expected positions: +- You can use [list patterns](patterns.md#list-patterns) to match elements of a list or array. The following code checks arrays for integer values in expected positions: :::code language="csharp" source="snippets/shared/IsOperator.cs" id="ListPatterns"::: diff --git a/docs/csharp/language-reference/operators/nameof.md b/docs/csharp/language-reference/operators/nameof.md index 1b1f2214b8201..88241d4380e81 100644 --- a/docs/csharp/language-reference/operators/nameof.md +++ b/docs/csharp/language-reference/operators/nameof.md @@ -1,7 +1,7 @@ --- title: "The nameof expression - evaluate the text name of a symbol" description: "The C# `nameof` expression produces the name of its operand. You use it whenever you need to use the name of a symbol as text" -ms.date: 02/19/2025 +ms.date: 11/18/2025 f1_keywords: - "nameof_CSharpKeyword" - "nameof" @@ -20,7 +20,7 @@ The preceding example using `List<>` is supported in C# 14 and later. You can us :::code language="csharp" source="snippets/shared/NameOfOperator.cs" id="ExceptionMessage"::: -Beginning with C# 11, you can use a `nameof` expression with a method parameter inside an [attribute](../../advanced-topics/reflection-and-attributes/index.md) on a method or its parameter. The following code shows how to do that for an attribute on a method, a local function, and the parameter of a lambda expression: +You can use a `nameof` expression with a method parameter inside an [attribute](../../advanced-topics/reflection-and-attributes/index.md) on a method or its parameter. The following code shows how to do that for an attribute on a method, a local function, and the parameter of a lambda expression: :::code language="csharp" source="snippets/shared/NameOfOperator.cs" id="SnippetNameOfParameter"::: @@ -32,7 +32,7 @@ When the operand is a [verbatim identifier](../tokens/verbatim.md), the `@` char ## C# language specification -For more information, see the [Nameof expressions](~/_csharpstandard/standard/expressions.md#12823-the-nameof-operator) section of the [C# language specification](~/_csharpstandard/standard/README.md), and the [C# 11 - Extended `nameof` scope](~/_csharplang/proposals/csharp-11.0/extended-nameof-scope.md) feature specification. +For more information, see the [Nameof expressions](~/_csharpstandard/standard/expressions.md#12823-the-nameof-operator) section of the [C# language specification](~/_csharpstandard/standard/README.md), and the [Extended `nameof` scope](~/_csharplang/proposals/csharp-11.0/extended-nameof-scope.md) feature specification. ## See also diff --git a/docs/csharp/language-reference/operators/patterns.md b/docs/csharp/language-reference/operators/patterns.md index 2e4a7cdb20deb..fa4d61ac43968 100644 --- a/docs/csharp/language-reference/operators/patterns.md +++ b/docs/csharp/language-reference/operators/patterns.md @@ -1,7 +1,7 @@ --- title: "Patterns - Pattern matching using the is and switch expressions." description: "Learn about the patterns supported by the `is` and `switch` expressions. Combine multiple patterns using the `and`, `or`, and `not` operators." -ms.date: 02/18/2025 +ms.date: 11/18/2025 f1_keywords: - "and_CSharpKeyword" - "or_CSharpKeyword" @@ -33,7 +33,7 @@ In those constructs, you can match an input expression against any of the follow - [Positional pattern](#positional-pattern): deconstruct an expression result and test if the resulting values match nested patterns. - [`var` pattern](#var-pattern): match any expression and assign its result to a declared variable. - [Discard pattern](#discard-pattern): match any expression. -- [List patterns](#list-patterns): test that a sequence of elements matches corresponding nested patterns. Introduced in C# 11. +- [List patterns](#list-patterns): test that a sequence of elements matches corresponding nested patterns. [Logical](#logical-patterns), [property](#property-pattern), [positional](#positional-pattern), and [list](#list-patterns) patterns are *recursive* patterns. That is, they can contain *nested* patterns. @@ -41,14 +41,14 @@ For the example of how to use those patterns to build a data-driven algorithm, s ## Declaration and type patterns -You use declaration and type patterns to check if the run-time type of an expression is compatible with a given type. With a declaration pattern, you can also declare a new local variable. When a declaration pattern matches an expression, that variable is assigned a converted expression result, as the following example shows: +You use declaration and type patterns to check if the run-time type of an expression is compatible with a given type. With a declaration pattern, you can also declare a new local variable. When a declaration pattern matches an expression, that variable is assigned to the converted expression result, as the following example shows: :::code language="csharp" source="snippets/patterns/DeclarationAndTypePatterns.cs" id="BasicExample"::: A *declaration pattern* with type `T` matches an expression when an expression result is non-null and any of the following conditions are true: - The run-time type of an expression result has an identity conversion to `T`. -- The type `T` is a `ref struct` type and there is an identity conversion from the expression to `T`. +- The type `T` is a `ref struct` type and there's an identity conversion from the expression to `T`. - The run-time type of an expression result derives from type `T`, implements interface `T`, or another [implicit reference conversion](~/_csharpstandard/standard/conversions.md#1028-implicit-reference-conversions) exists from it to `T`. This covers inheritance relationships and interface implementations. The following example demonstrates two cases when this condition is true: :::code language="csharp" source="snippets/patterns/DeclarationAndTypePatterns.cs" id="ReferenceConversion"::: In the preceding example, at the first call to the `GetSourceLabel` method, the first pattern matches an argument value because the argument's run-time type `int[]` derives from the type. At the second call to the `GetSourceLabel` method, the argument's run-time type doesn't derive from the type but implements the interface. @@ -93,7 +93,7 @@ In a constant pattern, you can use any constant expression, such as: - the name of a declared [const](../keywords/const.md) field or local - `null` -The expression must be a type that is convertible to the constant type, with one exception: An expression whose type is `Span` or `ReadOnlySpan` can be matched against constant strings in C# 11 and later versions. +The expression must be a type that's convertible to the constant type, with one exception: An expression whose type is `Span` or `ReadOnlySpan` can be matched against constant strings. Use a constant pattern to check for `null`, as the following example shows: @@ -182,7 +182,7 @@ You can also add a run-time type check and a variable declaration to a property :::code language="csharp" source="snippets/patterns/PropertyPattern.cs" id="WithTypeCheck"::: -This specifically means that the *empty* property pattern `is { }` matches everything non-null, and can be used instead of the `is not null` to create a variable: `somethingPossiblyNull is { } somethingDefinitelyNotNull`. +This construct specifically means that the *empty* property pattern `is { }` matches everything non-null, and can be used instead of the `is not null` to create a variable: `somethingPossiblyNull is { } somethingDefinitelyNotNull`. :::code language="csharp" source="snippets/patterns/PropertyPattern.cs" id="EmptyPropertyPattern"::: @@ -210,7 +210,7 @@ You use a *positional pattern* to deconstruct an expression result and match the At the preceding example, the type of an expression contains the [Deconstruct](../../fundamentals/functional/deconstruct.md) method, which is used to deconstruct an expression result. >[!IMPORTANT] -> The order of members in a positional pattern must match the order of parameters in the `Deconstruct` method. That's because the code generated for the positional pattern calls the `Deconstruct` method. +> The order of members in a positional pattern must match the order of parameters in the `Deconstruct` method. The code generated for the positional pattern calls the `Deconstruct` method. You can also match expressions of [tuple types](../builtin-types/value-tuples.md) against positional patterns. In that way, you can match multiple inputs against various patterns, as the following example shows: @@ -278,7 +278,7 @@ You can put parentheses around any pattern. Typically, you do that to emphasize ## List patterns -Beginning with C# 11, you can match an array or a list against a *sequence* of patterns, as the following example shows: +You can match an array or a list against a *sequence* of patterns, as the following example shows: :::code language="csharp" source="snippets/patterns/ListPattern.cs" id="BasicExample"::: @@ -306,8 +306,8 @@ For information about features added in C# 8 and later, see the following featur - [Pattern-matching updates](~/_csharplang/proposals/csharp-9.0/patterns3.md) - [Extended property patterns](~/_csharplang/proposals/csharp-10.0/extended-property-patterns.md) -- [C# 11 - List patterns](~/_csharplang/proposals/csharp-11.0/list-patterns.md) -- [C# 11 - Pattern match `Span` on string literal](~/_csharplang/proposals/csharp-11.0/pattern-match-span-of-char-on-string.md) +- [List patterns](~/_csharplang/proposals/csharp-11.0/list-patterns.md) +- [Pattern match `Span` on string literal](~/_csharplang/proposals/csharp-11.0/pattern-match-span-of-char-on-string.md) ## See also diff --git a/docs/csharp/language-reference/operators/user-defined-conversion-operators.md b/docs/csharp/language-reference/operators/user-defined-conversion-operators.md index b8e0f4046708e..f35f781331769 100644 --- a/docs/csharp/language-reference/operators/user-defined-conversion-operators.md +++ b/docs/csharp/language-reference/operators/user-defined-conversion-operators.md @@ -1,7 +1,7 @@ --- title: "User-defined explicit and implicit conversion operators - provide conversions to different types" description: "Learn how to define custom implicit and explicit type conversions in C#. The operators provide the functionality for casting an object to a new type." -ms.date: 02/19/2025 +ms.date: 11/18/2025 f1_keywords: - "explicit_CSharpKeyword" - "implicit_CSharpKeyword" @@ -25,7 +25,7 @@ The following example demonstrates how to define an implicit and explicit conver :::code language="csharp" source="snippets/shared/UserDefinedConversions.cs"::: -Beginning with C# 11, you can define *checked* explicit conversion operators. For more information, see the [User-defined checked operators](arithmetic-operators.md#user-defined-checked-operators) section of the [Arithmetic operators](arithmetic-operators.md) article. +You can define *checked* explicit conversion operators. For more information, see the [User-defined checked operators](arithmetic-operators.md#user-defined-checked-operators) section of the [Arithmetic operators](arithmetic-operators.md) article. You also use the `operator` keyword to overload a predefined C# operator. For more information, see [Operator overloading](operator-overloading.md). diff --git a/docs/csharp/language-reference/statements/checked-and-unchecked.md b/docs/csharp/language-reference/statements/checked-and-unchecked.md index 40cf148c4de74..8b01065f82943 100644 --- a/docs/csharp/language-reference/statements/checked-and-unchecked.md +++ b/docs/csharp/language-reference/statements/checked-and-unchecked.md @@ -1,7 +1,7 @@ --- title: "The checked and unchecked statements - overflow-checking" description: "Control the overflow-checking context. In a checked context, overflow causes an exception to be thrown. In an unchecked context, the result is truncated." -ms.date: 10/29/2022 +ms.date: 11/18/2025 f1_keywords: - "checked_CSharpKeyword" - "unchecked_CSharpKeyword" @@ -52,7 +52,7 @@ The overflow-checking context affects the following operations: > [!NOTE] > When you convert a `decimal` value to an integral type and the result is outside the range of the destination type, an is always thrown, regardless of the overflow-checking context. -- Beginning with C# 11, user-defined checked operators and conversions. For more information, see the [User-defined checked operators](../operators/arithmetic-operators.md#user-defined-checked-operators) section of the [Arithmetic operators](../operators/arithmetic-operators.md) article. +- User-defined checked operators and conversions. For more information, see the [User-defined checked operators](../operators/arithmetic-operators.md#user-defined-checked-operators) section of the [Arithmetic operators](../operators/arithmetic-operators.md) article. ## Default overflow-checking context @@ -66,7 +66,7 @@ For more information, see the following sections of the [C# language specificati - [The checked and unchecked statements](~/_csharpstandard/standard/statements.md#1312-the-checked-and-unchecked-statements) - [The checked and unchecked operators](~/_csharpstandard/standard/expressions.md#12820-the-checked-and-unchecked-operators) -- [User-defined checked and unchecked operators - C# 11](~/_csharplang/proposals/csharp-11.0/checked-user-defined-operators.md) +- [User-defined checked and unchecked operators](~/_csharplang/proposals/csharp-11.0/checked-user-defined-operators.md) ## See also diff --git a/docs/csharp/language-reference/tokens/interpolated.md b/docs/csharp/language-reference/tokens/interpolated.md index 72b6aede9c743..2f22f72c9f61c 100644 --- a/docs/csharp/language-reference/tokens/interpolated.md +++ b/docs/csharp/language-reference/tokens/interpolated.md @@ -1,7 +1,7 @@ --- title: "$ - string interpolation - format string output" description: String interpolation using the `$` token provides a more readable and convenient syntax to format string output than traditional string composite formatting. -ms.date: 10/07/2025 +ms.date: 11/18/2025 f1_keywords: - "$_CSharpKeyword" - "$" @@ -44,13 +44,13 @@ The following example uses optional formatting components described in the prece :::code language="csharp" interactive="try-dotnet-method" source="./snippets/string-interpolation.cs" id="AlignAndSpecifyFormat"::: -Beginning with C# 11, you can use new-lines within an interpolation expression to make the expression's code more readable. The following example shows how new-lines can improve the readability of an expression involving [pattern matching](../operators/patterns.md): +You can use new-lines within an interpolation expression to make the expression's code more readable. The following example shows how new-lines can improve the readability of an expression involving [pattern matching](../operators/patterns.md): :::code language="csharp" source="./snippets/string-interpolation.cs" id="MultiLineExpression"::: ## Interpolated raw string literals -Beginning with C# 11, you can use an interpolated [raw string literal](../builtin-types/reference-types.md#string-literals), as the following example shows: +You can use an interpolated [raw string literal](../builtin-types/reference-types.md#string-literals), as the following example shows: :::code language="csharp" source="./snippets/string-interpolation.cs" id="InterpolatedRawStringLiteral"::: @@ -66,7 +66,7 @@ In the preceding example, an interpolated raw string literal starts with two `$` To include a brace, "{" or "}", in the text produced by an interpolated string, use two braces, "{{" or "}}". For more information, see the [Escaping braces](../../../standard/base-types/composite-formatting.md#escaping-braces) section of the [Composite formatting](../../../standard/base-types/composite-formatting.md) article. -As the colon (":") has special meaning in an interpolation expression item, to use a [conditional operator](../operators/conditional-operator.md) in an interpolation expression, enclose that expression in parentheses. +As the colon (":") has special meaning in an interpolation expression item. To use a [conditional operator](../operators/conditional-operator.md) in an interpolation expression, enclose that expression in parentheses. The following example shows how to include a brace in a result string. It also shows how to use a conditional operator: @@ -108,8 +108,8 @@ If an interpolated string has the type or [!div class="checklist"] > @@ -27,40 +27,38 @@ This tutorial assumes you're familiar with C# and .NET, including either Visual In this tutorial, you'll build a library that models running a survey. The code uses both nullable reference types and non-nullable reference types to represent the real-world concepts. The survey questions can never be null. A respondent might prefer not to answer a question. The responses might be `null` in this case. -The code you'll write for this sample expresses that intent, and the compiler enforces that intent. +The code you write for this sample expresses that intent, and the compiler enforces that intent. ## Create the application and enable nullable reference types -Create a new console application either in Visual Studio or from the command line using `dotnet new console`. Name the application `NullableIntroduction`. Once you've created the application, you'll need to specify that the entire project compiles in an enabled **nullable annotation context**. Open the *.csproj* file and add a `Nullable` element to the `PropertyGroup` element. Set its value to `enable`. You must opt in to the **nullable reference types** feature in projects earlier than C# 11. That's because once the feature is turned on, existing reference variable declarations become **non-nullable reference types**. While that decision will help find issues where existing code may not have proper null-checks, it may not accurately reflect your original design intent: +Create a new console application either in Visual Studio or from the command line using `dotnet new console`. Name the application `NullableIntroduction`. Once you created the application, you need to specify that the entire project compiles in an enabled **nullable annotation context**. Open the *.csproj* file and add a `Nullable` element to the `PropertyGroup` element. Set its value to `enable`. You must opt in to the **nullable reference types** feature in projects created before C# 11 / .NET 7. Once the feature is turned on, existing reference variable declarations become **non-nullable reference types**. While that decision helps find issues where existing code might not have proper null-checks, it might not accurately reflect your original design intent: ```xml enable ``` -Prior to .NET 6, new projects do not include the `Nullable` element. Beginning with .NET 6, new projects include the `enable` element in the project file. - ### Design the types for the application -This survey application requires creating a number of classes: +This survey application requires creating these classes: - A class that models the list of questions. - A class that models a list of people contacted for the survey. - A class that models the answers from a person that took the survey. -These types will make use of both nullable and non-nullable reference types to express which members are required and which members are optional. Nullable reference types communicate that design intent clearly: +These types make use of both nullable and non-nullable reference types to express which members are required and which members are optional. Nullable reference types communicate that design intent clearly: - The questions that are part of the survey can never be null: It makes no sense to ask an empty question. -- The respondents can never be null. You'll want to track people you contacted, even respondents that declined to participate. -- Any response to a question may be null. Respondents can decline to answer some or all questions. +- The respondents can never be null. You want to track people you contacted, even respondents that declined to participate. +- Any response to a question might be null. Respondents can decline to answer some or all questions. -If you've programmed in C#, you may be so accustomed to reference types that allow `null` values that you may have missed other opportunities to declare non-nullable instances: +You might be so accustomed to reference types that allow `null` values that you might miss other opportunities to declare non-nullable instances: - The collection of questions should be non-nullable. - The collection of respondents should be non-nullable. -As you write the code, you'll see that a non-nullable reference type as the default for references avoids common mistakes that could lead to s. One lesson from this tutorial is that you made decisions about which variables could or could not be `null`. The language didn't provide syntax to express those decisions. Now it does. +As you write the code, you see that a non-nullable reference type as the default for references avoids common mistakes that could lead to s. One lesson from this tutorial is that you made decisions about which variables could or couldn't be `null`. The language didn't provide syntax to express those decisions. Now it does. -The app you'll build does the following steps: +The app you build does the following steps: 1. Creates a survey and adds questions to it. 1. Creates a pseudo-random set of respondents for the survey. @@ -69,7 +67,7 @@ The app you'll build does the following steps: ## Build the survey with nullable and non-nullable reference types -The first code you'll write creates the survey. You'll write classes to model a survey question and a survey run. Your survey has three types of questions, distinguished by the format of the answer: Yes/No answers, number answers, and text answers. Create a `public SurveyQuestion` class: +The first code you write creates the survey. You write classes to model a survey question and a survey run. Your survey has three types of questions, distinguished by the format of the answer: Yes/No answers, number answers, and text answers. Create a `public SurveyQuestion` class: ```csharp namespace NullableIntroduction @@ -100,7 +98,7 @@ namespace NullableIntroduction } ``` -Because you haven't initialized `QuestionText`, the compiler issues a warning that a non-nullable property hasn't been initialized. Your design requires the question text to be non-null, so you add a constructor to initialize it and the `QuestionType` value as well. The finished class definition looks like the following code: +Because you didn't initialized `QuestionText`, the compiler issues a warning that a non-nullable property wasn't initialized. Your design requires the question text to be non-null, so you add a constructor to initialize it and the `QuestionType` value as well. The finished class definition looks like the following code: :::code language="csharp" source="./snippets/NullableIntroduction/SurveyQuestion.cs"::: @@ -124,13 +122,13 @@ namespace NullableIntroduction } ``` -As before, you must initialize the list object to a non-null value or the compiler issues a warning. There are no null checks in the second overload of `AddQuestion` because the compiler helps enforce the non-nullable contract: You've declared that variable to be non-nullable. While the compiler warns about potential null assignments, runtime null values are still possible. For public APIs, consider adding argument validation even for non-nullable reference types, since client code might not have nullable reference types enabled or could intentionally pass null. +As before, you must initialize the list object to a non-null value or the compiler issues a warning. There are no null checks in the second overload of `AddQuestion` because the compiler helps enforce the non-nullable contract: You declared that variable to be non-nullable. While the compiler warns about potential null assignments, runtime null values are still possible. For public APIs, consider adding argument validation even for non-nullable reference types, since client code might not have nullable reference types enabled or could intentionally pass null. Switch to *Program.cs* in your editor and replace the contents of `Main` with the following lines of code: :::code language="csharp" source="./snippets/NullableIntroduction/Program.cs" id="AddQuestions"::: -Because the entire project is in an enabled nullable annotation context, you'll get warnings when you pass `null` to any method expecting a non-nullable reference type. Try it by adding the following line to `Main`: +Because the entire project is in an enabled nullable annotation context, you get warnings when you pass `null` to any method expecting a non-nullable reference type. Try it by adding the following line to `Main`: ```csharp surveyRun.AddQuestion(QuestionType.Text, default); @@ -140,11 +138,11 @@ surveyRun.AddQuestion(QuestionType.Text, default); Next, write the code that generates answers to the survey. This process involves several small tasks: -1. Build a method that generates respondent objects. These represent people asked to fill out the survey. +1. Build a method that generates respondent objects. These objects represent people asked to fill out the survey. 1. Build logic to simulate asking the questions to a respondent and collecting answers or noting that a respondent didn't answer. -1. Repeat until enough respondents have answered the survey. +1. Repeat until enough respondents answer the survey. -You'll need a class to represent a survey response, so add that now. Enable nullable support. Add an `Id` property and a constructor that initializes it, as shown in the following code: +You need a class to represent a survey response, so add that now. Enable nullable support. Add an `Id` property and a constructor that initializes it, as shown in the following code: ```csharp namespace NullableIntroduction @@ -165,21 +163,21 @@ Next, add a `static` method to create new participants by generating a random ID The main responsibility of this class is to generate the responses for a participant to the questions in the survey. This responsibility has a few steps: 1. Ask for participation in the survey. If the person doesn't consent, return a missing (or null) response. -1. Ask each question and record the answer. Each answer may also be missing (or null). +1. Ask each question and record the answer. Each answer might also be missing (or null). Add the following code to your `SurveyResponse` class: :::code language="csharp" source="./snippets/NullableIntroduction/SurveyResponse.cs" id="AnswerSurvey"::: -The storage for the survey answers is a `Dictionary?`, indicating that it may be null. You're using the new language feature to declare your design intent, both to the compiler and to anyone reading your code later. If you ever dereference `surveyResponses` without checking for the `null` value first, you'll get a compiler warning. You don't get a warning in the `AnswerSurvey` method because the compiler can determine the `surveyResponses` variable was set to a non-null value above. +The storage for the survey answers is a `Dictionary?`, indicating that it might be null. You're using the new language feature to declare your design intent, both to the compiler and to anyone reading your code later. If you ever dereference `surveyResponses` without checking for the `null` value first, you get a compiler warning. You don't get a warning in the `AnswerSurvey` method because the compiler can determine the `surveyResponses` variable was set to a non-null value in the preceding code. -Using `null` for missing answers highlights a key point for working with nullable reference types: your goal isn't to remove all `null` values from your program. Rather, your goal is to ensure that the code you write expresses the intent of your design. Missing values are a necessary concept to express in your code. The `null` value is a clear way to express those missing values. Trying to remove all `null` values only leads to defining some other way to express those missing values without `null`. +Using `null` for missing answers highlights a key point for working with nullable reference types: your goal isn't to remove all `null` values from your program. Rather, your goal is to ensure that the code you write expresses the intent of your design. Missing values are a necessary concept to express in your code. The `null` value is a clear way to express those missing values. Trying to remove all `null` values leads to defining some other way to express those missing values without `null`. Next, you need to write the `PerformSurvey` method in the `SurveyRun` class. Add the following code in the `SurveyRun` class: :::code language="csharp" source="./snippets/NullableIntroduction/SurveyRun.cs" id="PerformSurvey"::: -Here again, your choice of a nullable `List?` indicates the response may be null. That indicates the survey hasn't been given to any respondents yet. Notice that respondents are added until enough have consented. +Here again, your choice of a nullable `List?` indicates the response might be null. That indicates the survey hasn't been given to any respondents yet. Notice that respondents are added until enough consent. The last step to run the survey is to add a call to perform the survey at the end of the `Main` method: @@ -187,7 +185,7 @@ The last step to run the survey is to add a call to perform the survey at the en ## Examine survey responses -The last step is to display survey results. You'll add code to many of the classes you've written. This code demonstrates the value of distinguishing nullable and non-nullable reference types. Start by adding the following two expression-bodied members to the `SurveyResponse` class: +The last step is to display survey results. You add code to many of the classes you wrote. This code demonstrates the value of distinguishing nullable and non-nullable reference types. Start by adding the following two expression-bodied members to the `SurveyResponse` class: :::code language="csharp" source="./snippets/NullableIntroduction/SurveyResponse.cs" id="SurveyStatus"::: @@ -203,7 +201,7 @@ Finally, add the following loop at the bottom of the `Main` method: :::code language="csharp" source="./snippets/NullableIntroduction/Program.cs" id="WriteAnswers"::: -You don't need any `null` checks in this code because you've designed the underlying interfaces so that they all return non-nullable reference types. The compiler's static analysis helps ensure these design contracts are followed. +You don't need any `null` checks in this code because you designed the underlying interfaces so that they all return non-nullable reference types. The compiler's static analysis helps ensure these design contracts are followed. ## Get the code diff --git a/docs/csharp/tutorials/string-interpolation.md b/docs/csharp/tutorials/string-interpolation.md index 65e2624751a24..86b251440408a 100644 --- a/docs/csharp/tutorials/string-interpolation.md +++ b/docs/csharp/tutorials/string-interpolation.md @@ -3,7 +3,7 @@ title: String interpolation description: Learn how to include formatted expression results in a result string in C# with string interpolation. author: pkulikov ms.subservice: fundamentals -ms.date: 05/05/2025 +ms.date: 11/18/2025 --- # String interpolation in C\# @@ -85,7 +85,7 @@ The following example shows how to include braces in a result string and constru :::code language="csharp" interactive="try-dotnet-method" source="./snippets/StringInterpolation/Program.cs" id="Escapes"::: -Beginning with C# 11, you can use [interpolated raw string literals](../language-reference/tokens/interpolated.md#interpolated-raw-string-literals). +You can use [interpolated raw string literals](../language-reference/tokens/interpolated.md#interpolated-raw-string-literals). ## How to use a ternary conditional operator `?:` in an interpolation expression diff --git a/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md b/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md index f1811e3b1260b..c4131a86b196a 100644 --- a/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md +++ b/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md @@ -1,14 +1,14 @@ --- title: Explore static virtual members in C# interfaces description: This advanced tutorial demonstrates scenarios for operators and other static members in interfaces. -ms.date: 07/08/2022 +ms.date: 11/18/2025 ms.subservice: advanced-concepts --- -# Tutorial: Explore C# 11 feature - static virtual members in interfaces +# Tutorial: Explore static virtual members in interfaces -C# 11 and .NET 7 include *static virtual members in interfaces*. This feature enables you to define interfaces that include [overloaded operators](../../language-reference/operators/operator-overloading.md) or other static members. Once you've defined interfaces with static members, you can use those interfaces as [constraints](../../programming-guide/generics/constraints-on-type-parameters.md) to create generic types that use operators or other static methods. Even if you don't create interfaces with overloaded operators, you'll likely benefit from this feature and the generic math classes enabled by the language update. +*Interface static virtual members* enable you to define interfaces that include [overloaded operators](../../language-reference/operators/operator-overloading.md) or other static members. Once you define interfaces with static members, you can use those interfaces as [constraints](../../programming-guide/generics/constraints-on-type-parameters.md) to create generic types that use operators or other static methods. Even if you don't create interfaces with overloaded operators, you likely benefit from this feature and the generic math classes enabled by the language update. -In this tutorial, you'll learn how to: +In this tutorial, you learn how to: > [!div class="checklist"] > @@ -45,7 +45,7 @@ You can create a structure that creates a string of 'A' characters where each in :::code language="csharp" source="./snippets/staticinterfaces/RepeatSequence.cs"::: -More generally, you can build any algorithm where you might want to define `++` to mean "produce the next value of this type". Using this interface produces clear code and results: +More generally, you can build any algorithm where you might want to define `++` to mean "produce the next value of this type." Using this interface produces clear code and results: :::code language="csharp" source="./snippets/staticinterfaces/Program.cs" id="TestRepeat"::: @@ -68,7 +68,7 @@ This small example demonstrates the motivation for this feature. You can use nat ## Generic math -The motivating scenario for allowing static methods, including operators, in interfaces is to support [generic math](../../../standard/generics/math.md) algorithms. The .NET 7 base class library contains interface definitions for many arithmetic operators, and derived interfaces that combine many arithmetic operators in an `INumber` interface. Let's apply those types to build a `Point` record that can use any numeric type for `T`. The point can be moved by some `XOffset` and `YOffset` using the `+` operator. +The motivating scenario for allowing static methods, including operators, in interfaces is to support [generic math](../../../standard/generics/math.md) algorithms. The .NET 7 base class library contains interface definitions for many arithmetic operators, and derived interfaces that combine many arithmetic operators in an `INumber` interface. Let's apply those types to build a `Point` record that can use any numeric type for `T`. You can move the point by some `XOffset` and `YOffset` using the `+` operator. Start by creating a new Console application, either by using `dotnet new` or Visual Studio. @@ -91,7 +91,7 @@ public static Point operator +(Point left, Translation right) => left with { X = left.X + right.XOffset, Y = left.Y + right.YOffset }; ``` -For the previous code to compile, you'll need to declare that `T` supports the `IAdditionOperators` interface. That interface includes the `operator +` static method. It declares three type parameters: One for the left operand, one for the right operand, and one for the result. Some types implement `+` for different operand and result types. Add a declaration that the type argument, `T` implements `IAdditionOperators`: +For the previous code to compile, you need to declare that `T` supports the `IAdditionOperators` interface. That interface includes the `operator +` static method. It declares three type parameters: One for the left operand, one for the right operand, and one for the result. Some types implement `+` for different operand and result types. Add a declaration that the type argument, `T` implements `IAdditionOperators`: ```csharp public record Point(T X, T Y) where T : IAdditionOperators @@ -103,7 +103,7 @@ After you add that constraint, your `Point` class can use the `+` for its add public record Translation(T XOffset, T YOffset) where T : IAdditionOperators; ``` -The `IAdditionOperators` constraint prevents a developer using your class from creating a `Translation` using a type that doesn't meet the constraint for the addition to a point. You've added the necessary constraints to the type parameter for `Translation` and `Point` so this code works. You can test by adding code like the following above the declarations of `Translation` and `Point` in your *Program.cs* file: +The `IAdditionOperators` constraint prevents a developer using your class from creating a `Translation` using a type that doesn't meet the constraint for the addition to a point. You added the necessary constraints to the type parameter for `Translation` and `Point` so this code works. You can test by adding code like the following above the declarations of `Translation` and `Point` in your *Program.cs* file: :::code language="csharp" source="./snippets/staticinterfaces/Program.cs" id="TestAddition"::: @@ -131,18 +131,18 @@ public static Translation AdditiveIdentity => new Translation(XOffset: 0, YOffset: 0); ``` -The preceding code won't compile, because `0` depends on the type. The answer: Use `IAdditiveIdentity.AdditiveIdentity` for `0`. That change means that your constraints must now include that `T` implements `IAdditiveIdentity`. That results in the following implementation: +The preceding code doesn't compile, because `0` depends on the type. The answer: Use `IAdditiveIdentity.AdditiveIdentity` for `0`. That change means that your constraints must now include that `T` implements `IAdditiveIdentity`. That results in the following implementation: ```csharp public static Translation AdditiveIdentity => new Translation(XOffset: T.AdditiveIdentity, YOffset: T.AdditiveIdentity); ``` -Now that you've added that constraint on `Translation`, you need to add the same constraint to `Point`: +Now that you added that constraint on `Translation`, you need to add the same constraint to `Point`: :::code language="csharp" source="./snippets/staticinterfaces/Point.cs"::: -This sample has given you a look at how the interfaces for generic math compose. You learned how to: +This sample gave you a look at how the interfaces for generic math compose. You learned how to: > [!div class="checklist"] > @@ -150,7 +150,7 @@ This sample has given you a look at how the interfaces for generic math compose. > * Build a type that relies on the addition interfaces to implement a type that only supports one mathematical operation. > That type declares its support for those same interfaces so it can be composed in other ways. The algorithms are written using the most natural syntax of mathematical operators. -Experiment with these features and register feedback. You can use the *Send Feedback* menu item in Visual Studio, or create a new [issue](https://github.com/dotnet/roslyn/issues/new/choose) in the roslyn repository on GitHub. Build generic algorithms that work with any numeric type. Build algorithms using these interfaces where the type argument may only implement a subset of number-like capabilities. Even if you don't build new interfaces that use these capabilities, you can experiment with using them in your algorithms. +Experiment with these features and register feedback. You can use the *Send Feedback* menu item in Visual Studio, or create a new [issue](https://github.com/dotnet/roslyn/issues/new/choose) in the roslyn repository on GitHub. Build generic algorithms that work with any numeric type. Build algorithms using these interfaces where the type argument only implements a subset of number-like capabilities. Even if you don't build new interfaces that use these capabilities, you can experiment with using them in your algorithms. ## See also From cdfe715b704a13f0eff2fde1f90a0d0b97c5036d Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 16:57:29 -0500 Subject: [PATCH 03/10] Fix warnings --- docs/csharp/whats-new/csharp-version-history.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/csharp/whats-new/csharp-version-history.md b/docs/csharp/whats-new/csharp-version-history.md index 0d15abf11c656..ec79a68b4e3af 100644 --- a/docs/csharp/whats-new/csharp-version-history.md +++ b/docs/csharp/whats-new/csharp-version-history.md @@ -19,14 +19,14 @@ This article provides a history of each major release of the C# language. The C# C# 14 includes the following new features: -- [Extension members](./csharp14.md#extension-members) -- [Null-conditional assignment](./csharp14.md#null-conditional-assignment) -- [`nameof` supports unbound generic types](./csharp14.md#unbound-generic-types-and-nameof) -- [More implicit conversions for `Span` and `ReadOnlySpan`](./csharp14.md#implicit-span-conversions) -- [Modifiers on simple lambda parameters](./csharp14.md#simple-lambda-parameters-with-modifiers) -- [`field` backed properties](./csharp14.md#the-field-keyword) -- [`partial` events and constructors](./csharp14.md#more-partial-members) -- [user-defined compound assignment operators](./csharp14.md#user-defined-compound-assignment) +- [Extension members](./csharp-14.md#extension-members) +- [Null-conditional assignment](./csharp-14.md#null-conditional-assignment) +- [`nameof` supports unbound generic types](./csharp-14.md#unbound-generic-types-and-nameof) +- [More implicit conversions for `Span` and `ReadOnlySpan`](./csharp-14.md#implicit-span-conversions) +- [Modifiers on simple lambda parameters](./csharp-14.md#simple-lambda-parameters-with-modifiers) +- [`field` backed properties](./csharp-14.md#the-field-keyword) +- [`partial` events and constructors](./csharp-14.md#more-partial-members) +- [user-defined compound assignment operators](./csharp-14.md#user-defined-compound-assignment) ## C# version 13 From 27c259e7272ced86d29251eac1afdad596a5b000 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 17:15:18 -0500 Subject: [PATCH 04/10] more warnings.. --- docs/csharp/whats-new/csharp-version-history.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/csharp/whats-new/csharp-version-history.md b/docs/csharp/whats-new/csharp-version-history.md index ec79a68b4e3af..49aabd1aa8a92 100644 --- a/docs/csharp/whats-new/csharp-version-history.md +++ b/docs/csharp/whats-new/csharp-version-history.md @@ -110,11 +110,6 @@ C# 10 adds the following features and enhancements to the C# language: - [CallerArgumentExpression attribute](../language-reference/attributes/caller-information.md#argument-expressions) - C# 10 supports a new format for the `#line` pragma. -More features were available in *preview* mode. In order to use these features, you must [set `` to `Preview`](../language-reference/compiler-options/language.md#langversion) in your project: - -- [Generic attributes](./csharp-11.md#generic-attributes) later in this article. -- [static abstract members in interfaces](./csharp-11.md#generic-math-support). - C# 10 continues work on themes of removing ceremony, separating data from algorithms, and improved performance for the .NET Runtime. Many of the features mean you type less code to express the same concepts. *Record structs* synthesize many of the same methods that *record classes* do. Structs and anonymous types support *with expressions*. *Global using directives* and *file scoped namespace declarations* mean you express dependencies and namespace organization more clearly. *Lambda improvements* make it easier to declare lambda expressions where they're used. New property patterns and deconstruction improvements create more concise code. From 71b79ba624dd7216302a790b0d6bc3f7203f33f7 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 17:24:51 -0500 Subject: [PATCH 05/10] Move virtual static tutorial --- .openpublishing.redirection.csharp.json | 6 +++++- .../core-libraries/6.0/static-abstract-interface-methods.md | 2 +- .../snippets/staticinterfaces/GetNext.cs | 0 .../snippets/staticinterfaces/Point.cs | 0 .../snippets/staticinterfaces/Program.cs | 0 .../snippets/staticinterfaces/RepeatSequence.cs | 0 .../snippets/staticinterfaces/Translation.cs | 0 .../snippets/staticinterfaces/Utilities.cs | 0 .../snippets/staticinterfaces/staticinterfaces.csproj | 0 .../static-virtual-interface-members.md | 2 +- docs/csharp/toc.yml | 4 ++-- 11 files changed, 9 insertions(+), 5 deletions(-) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/snippets/staticinterfaces/GetNext.cs (100%) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/snippets/staticinterfaces/Point.cs (100%) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/snippets/staticinterfaces/Program.cs (100%) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/snippets/staticinterfaces/RepeatSequence.cs (100%) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/snippets/staticinterfaces/Translation.cs (100%) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/snippets/staticinterfaces/Utilities.cs (100%) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/snippets/staticinterfaces/staticinterfaces.csproj (100%) rename docs/csharp/{whats-new/tutorials => advanced-topics/interface-implementation}/static-virtual-interface-members.md (99%) diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index 02fb64f9c1222..8de2b70e6a6b7 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -4749,7 +4749,11 @@ }, { "source_path_from_root": "/docs/csharp/whats-new/tutorials/static-abstract-interface-methods.md", - "redirect_url": "/dotnet/csharp/whats-new/tutorials/static-virtual-interface-members" + "redirect_url": "/dotnet/advanced-topics/interface-implementation/static-virtual-interface-members" + }, + { + "source_path_from_root": "/docs/csharp/whats-new/tutorials/static-virtual-interface-methods.md", + "redirect_url": "/dotnet/advanced-topics/interface-implementation/static-virtual-interface-members" }, { "source_path_from_root": "/docs/csharp/whats-new/tutorials/top-level-statements.md", diff --git a/docs/core/compatibility/core-libraries/6.0/static-abstract-interface-methods.md b/docs/core/compatibility/core-libraries/6.0/static-abstract-interface-methods.md index 14d5c797d468e..8b6d3bd6896b2 100644 --- a/docs/core/compatibility/core-libraries/6.0/static-abstract-interface-methods.md +++ b/docs/core/compatibility/core-libraries/6.0/static-abstract-interface-methods.md @@ -47,4 +47,4 @@ N/A ## See also -- [Tutorial: Explore static virtual members in interfaces](../../../../csharp/whats-new/tutorials/static-virtual-interface-members.md) +- [Tutorial: Explore static virtual members in interfaces](../../../../csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md) diff --git a/docs/csharp/whats-new/tutorials/snippets/staticinterfaces/GetNext.cs b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/GetNext.cs similarity index 100% rename from docs/csharp/whats-new/tutorials/snippets/staticinterfaces/GetNext.cs rename to docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/GetNext.cs diff --git a/docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Point.cs b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Point.cs similarity index 100% rename from docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Point.cs rename to docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Point.cs diff --git a/docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Program.cs b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Program.cs similarity index 100% rename from docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Program.cs rename to docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Program.cs diff --git a/docs/csharp/whats-new/tutorials/snippets/staticinterfaces/RepeatSequence.cs b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/RepeatSequence.cs similarity index 100% rename from docs/csharp/whats-new/tutorials/snippets/staticinterfaces/RepeatSequence.cs rename to docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/RepeatSequence.cs diff --git a/docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Translation.cs b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Translation.cs similarity index 100% rename from docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Translation.cs rename to docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Translation.cs diff --git a/docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Utilities.cs b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Utilities.cs similarity index 100% rename from docs/csharp/whats-new/tutorials/snippets/staticinterfaces/Utilities.cs rename to docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Utilities.cs diff --git a/docs/csharp/whats-new/tutorials/snippets/staticinterfaces/staticinterfaces.csproj b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/staticinterfaces.csproj similarity index 100% rename from docs/csharp/whats-new/tutorials/snippets/staticinterfaces/staticinterfaces.csproj rename to docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/staticinterfaces.csproj diff --git a/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md b/docs/csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md similarity index 99% rename from docs/csharp/whats-new/tutorials/static-virtual-interface-members.md rename to docs/csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md index c4131a86b196a..2856019742d7a 100644 --- a/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md +++ b/docs/csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md @@ -18,7 +18,7 @@ In this tutorial, you learn how to: ## Prerequisites -[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic.md)] +[!INCLUDE [Prerequisites](../../../../includes/includes/prerequisites-basic.md)] ## Static abstract interface methods diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index 52e8b95da8f8e..5c43898d400c3 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -180,8 +180,6 @@ items: href: whats-new/tutorials/compound-assignment-operators.md - name: Explore primary constructors href: whats-new/tutorials/primary-constructors.md - - name: Explore static interface members - href: whats-new/tutorials/static-virtual-interface-members.md - name: Tutorials items: - name: Explore record types @@ -350,6 +348,8 @@ items: href: advanced-topics/interface-implementation/default-interface-methods-versions.md - name: Create mixin functionality with default interface methods href: advanced-topics/interface-implementation/mixins-with-default-interface-methods.md + - name: Explore static interface members + href: advanced-topics/interface-implementation/static-virtual-interface-members.md - name: Expression trees items: - name: Overview From 6e642d012dc216db972e729029f9bd447f42700f Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 17:27:25 -0500 Subject: [PATCH 06/10] Update tutorial code. --- .../snippets/staticinterfaces/Program.cs | 4 +--- .../snippets/staticinterfaces/staticinterfaces.csproj | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Program.cs b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Program.cs index 1be6412c1176b..f7b7c9721cc50 100644 --- a/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Program.cs +++ b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/Program.cs @@ -1,6 +1,4 @@ -// See https://aka.ms/new-console-template for more information - -Console.WriteLine(Utilities.MidPoint(12, 24)); +Console.WriteLine(Utilities.MidPoint(12, 24)); // var str = new RepeatSequence(); diff --git a/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/staticinterfaces.csproj b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/staticinterfaces.csproj index 2150e3797ba5e..ed9781c223ab9 100644 --- a/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/staticinterfaces.csproj +++ b/docs/csharp/advanced-topics/interface-implementation/snippets/staticinterfaces/staticinterfaces.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 enable enable From dc63c3c97194354229f95c6ae0cd39d6887fb324 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 17:34:25 -0500 Subject: [PATCH 07/10] fix warnings --- .../static-virtual-interface-members.md | 2 +- .../compiler-messages/static-abstract-interfaces.md | 2 +- docs/csharp/language-reference/keywords/interface.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md b/docs/csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md index 2856019742d7a..c4131a86b196a 100644 --- a/docs/csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md +++ b/docs/csharp/advanced-topics/interface-implementation/static-virtual-interface-members.md @@ -18,7 +18,7 @@ In this tutorial, you learn how to: ## Prerequisites -[!INCLUDE [Prerequisites](../../../../includes/includes/prerequisites-basic.md)] +[!INCLUDE [Prerequisites](../../../../includes/prerequisites-basic.md)] ## Static abstract interface methods diff --git a/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md b/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md index 16e56e726289b..114aa243c2dfe 100644 --- a/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md +++ b/docs/csharp/language-reference/compiler-messages/static-abstract-interfaces.md @@ -67,7 +67,7 @@ All these rules are extensions of the rules for declaring overloaded operators. For example, `INumber` can declare an `T operator++(T)` because `T` is constrained to implement `INumber`. -To fix these errors, ensure that the parameters of any operators defined in the interface obey these rules. You can learn more in the language reference article on [static abstract members in interfaces](../keywords/interface.md#static-abstract-and-virtual-members) or in the tutorial to [explore static abstract interface members](../../whats-new/tutorials/static-virtual-interface-members.md). +To fix these errors, ensure that the parameters of any operators defined in the interface obey these rules. You can learn more in the language reference article on [static abstract members in interfaces](../keywords/interface.md#static-abstract-and-virtual-members) or in the tutorial to [explore static abstract interface members](../../advanced-topics/interface-implementation/static-virtual-interface-members.md). ## Errors in type implementing interface declaration diff --git a/docs/csharp/language-reference/keywords/interface.md b/docs/csharp/language-reference/keywords/interface.md index c2903428e843a..71f727451c986 100644 --- a/docs/csharp/language-reference/keywords/interface.md +++ b/docs/csharp/language-reference/keywords/interface.md @@ -56,7 +56,7 @@ An interface can declare `static abstract` and `static virtual` members for all > [!IMPORTANT] > Method dispatch for `static abstract` and `static virtual` methods declared in interfaces is resolved using the compile time type of an expression. If the runtime type of an expression is derived from a different compile time type, the static methods on the base (compile time) type are called. -You can try this feature by working with the tutorial on [static abstract members in interfaces](../../whats-new/tutorials/static-virtual-interface-members.md). +You can try this feature by working with the tutorial on [static abstract members in interfaces](../../advanced-topics/interface-implementation/static-virtual-interface-members.md). ## Interface inheritance From c65f672c4112e6de97d4ad123a2bdf7a808463d7 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 18 Nov 2025 17:39:04 -0500 Subject: [PATCH 08/10] mispelled redirection --- .openpublishing.redirection.csharp.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index 8de2b70e6a6b7..c0d7466f0420a 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -4752,7 +4752,7 @@ "redirect_url": "/dotnet/advanced-topics/interface-implementation/static-virtual-interface-members" }, { - "source_path_from_root": "/docs/csharp/whats-new/tutorials/static-virtual-interface-methods.md", + "source_path_from_root": "/docs/csharp/whats-new/tutorials/static-virtual-interface-members.md", "redirect_url": "/dotnet/advanced-topics/interface-implementation/static-virtual-interface-members" }, { From f980360c1d997c6c6633abec75918584cb129c30 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 19 Nov 2025 09:55:58 -0500 Subject: [PATCH 09/10] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Meaghan Osagie (Lewis) --- docs/csharp/language-reference/attributes/nullable-analysis.md | 2 +- docs/csharp/language-reference/operators/delegate-operator.md | 2 +- .../language-reference/statements/checked-and-unchecked.md | 2 +- docs/csharp/language-reference/tokens/interpolated.md | 2 +- docs/csharp/tutorials/nullable-reference-types.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/csharp/language-reference/attributes/nullable-analysis.md b/docs/csharp/language-reference/attributes/nullable-analysis.md index 7bbabe8372aeb..513b8da04cec4 100644 --- a/docs/csharp/language-reference/attributes/nullable-analysis.md +++ b/docs/csharp/language-reference/attributes/nullable-analysis.md @@ -177,7 +177,7 @@ You specify conditional postconditions using these attributes: ## Helper methods: `MemberNotNull` and `MemberNotNullWhen` -These attributes specify your intent when you refactored common code from constructors into helper methods. The C# compiler analyzes constructors and field initializers to make sure that all non-nullable reference fields are before each constructor returns. However, the C# compiler doesn't track field assignments through all helper methods. The compiler issues warning `CS8618` when fields aren't initialized directly in the constructor, but rather in a helper method. You add the to a method declaration and specify the fields that are initialized to a non-null value in the method. For example, consider the following example: +These attributes specify your intent when you refactored common code from constructors into helper methods. The C# compiler analyzes constructors and field initializers to make sure that all non-nullable reference fields are initialized before each constructor returns. However, the C# compiler doesn't track field assignments through all helper methods. The compiler issues warning `CS8618` when fields aren't initialized directly in the constructor, but rather in a helper method. You add the to a method declaration and specify the fields that are initialized to a non-null value in the method. For example, consider the following example: :::code language="csharp" source="snippets/InitializeMembers.cs" ID="MemberNotNullExample"::: diff --git a/docs/csharp/language-reference/operators/delegate-operator.md b/docs/csharp/language-reference/operators/delegate-operator.md index 02721ad088e78..9533e615347bb 100644 --- a/docs/csharp/language-reference/operators/delegate-operator.md +++ b/docs/csharp/language-reference/operators/delegate-operator.md @@ -1,7 +1,7 @@ --- title: "delegate operator - Create an anonymous method that can be converted to a delegate type." description: "The C# delegate operator that is used to create anonymous methods. These types can be used for `Func<>` and `Action<>` parameters in many .NET APIs." -ms.date: 11/18/2022 +ms.date: 11/18/2025 helpviewer_keywords: - "delegate [C#]" - "anonymous method [C#]" diff --git a/docs/csharp/language-reference/statements/checked-and-unchecked.md b/docs/csharp/language-reference/statements/checked-and-unchecked.md index 8b01065f82943..72e577f0059f6 100644 --- a/docs/csharp/language-reference/statements/checked-and-unchecked.md +++ b/docs/csharp/language-reference/statements/checked-and-unchecked.md @@ -52,7 +52,7 @@ The overflow-checking context affects the following operations: > [!NOTE] > When you convert a `decimal` value to an integral type and the result is outside the range of the destination type, an is always thrown, regardless of the overflow-checking context. -- User-defined checked operators and conversions. For more information, see the [User-defined checked operators](../operators/arithmetic-operators.md#user-defined-checked-operators) section of the [Arithmetic operators](../operators/arithmetic-operators.md) article. +- You can use user-defined checked operators and conversions. For more information, see the [User-defined checked operators](../operators/arithmetic-operators.md#user-defined-checked-operators) section of the [Arithmetic operators](../operators/arithmetic-operators.md) article. ## Default overflow-checking context diff --git a/docs/csharp/language-reference/tokens/interpolated.md b/docs/csharp/language-reference/tokens/interpolated.md index 2f22f72c9f61c..d1cfe0d8fa800 100644 --- a/docs/csharp/language-reference/tokens/interpolated.md +++ b/docs/csharp/language-reference/tokens/interpolated.md @@ -66,7 +66,7 @@ In the preceding example, an interpolated raw string literal starts with two `$` To include a brace, "{" or "}", in the text produced by an interpolated string, use two braces, "{{" or "}}". For more information, see the [Escaping braces](../../../standard/base-types/composite-formatting.md#escaping-braces) section of the [Composite formatting](../../../standard/base-types/composite-formatting.md) article. -As the colon (":") has special meaning in an interpolation expression item. To use a [conditional operator](../operators/conditional-operator.md) in an interpolation expression, enclose that expression in parentheses. +The colon (":") has special meaning in an interpolation expression item. To use a [conditional operator](../operators/conditional-operator.md) in an interpolation expression, enclose that expression in parentheses. The following example shows how to include a brace in a result string. It also shows how to use a conditional operator: diff --git a/docs/csharp/tutorials/nullable-reference-types.md b/docs/csharp/tutorials/nullable-reference-types.md index 9c43f1c96c177..a80f684b83bc2 100644 --- a/docs/csharp/tutorials/nullable-reference-types.md +++ b/docs/csharp/tutorials/nullable-reference-types.md @@ -31,7 +31,7 @@ The code you write for this sample expresses that intent, and the compiler enfor ## Create the application and enable nullable reference types -Create a new console application either in Visual Studio or from the command line using `dotnet new console`. Name the application `NullableIntroduction`. Once you created the application, you need to specify that the entire project compiles in an enabled **nullable annotation context**. Open the *.csproj* file and add a `Nullable` element to the `PropertyGroup` element. Set its value to `enable`. You must opt in to the **nullable reference types** feature in projects created before C# 11 / .NET 7. Once the feature is turned on, existing reference variable declarations become **non-nullable reference types**. While that decision helps find issues where existing code might not have proper null-checks, it might not accurately reflect your original design intent: +Create a new console application either in Visual Studio or from the command line using `dotnet new console`. Name the application `NullableIntroduction`. Once you create the application, you need to specify that the entire project compiles in an enabled **nullable annotation context**. Open the *.csproj* file and add a `Nullable` element to the `PropertyGroup` element. Set its value to `enable`. You must opt in to the **nullable reference types** feature in projects created before C# 11 / .NET 7. Once the feature is turned on, existing reference variable declarations become **non-nullable reference types**. While that decision helps find issues where existing code might not have proper null-checks, it might not accurately reflect your original design intent: ```xml enable From c41efe6a06f0113ca10efbfb7ba383e0399ea15d Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Wed, 19 Nov 2025 10:00:56 -0500 Subject: [PATCH 10/10] respond to feedback. --- .../language-reference/operators/delegate-operator.md | 6 ------ docs/csharp/tutorials/nullable-reference-types.md | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/csharp/language-reference/operators/delegate-operator.md b/docs/csharp/language-reference/operators/delegate-operator.md index 9533e615347bb..a00b40f00df99 100644 --- a/docs/csharp/language-reference/operators/delegate-operator.md +++ b/docs/csharp/language-reference/operators/delegate-operator.md @@ -49,12 +49,6 @@ When you assign the method group to a delegate, the compiler caches the delegate Action a = StaticFunction; ``` -You'd need to use a lambda expression to reuse a single delegate object: - -```csharp -Action a = () => StaticFunction(); -``` - ## C# language specification For more information, see the [Anonymous function expressions](~/_csharpstandard/standard/expressions.md#1221-anonymous-function-expressions) section of the [C# language specification](~/_csharpstandard/standard/README.md). diff --git a/docs/csharp/tutorials/nullable-reference-types.md b/docs/csharp/tutorials/nullable-reference-types.md index a80f684b83bc2..afbc1e430e9a3 100644 --- a/docs/csharp/tutorials/nullable-reference-types.md +++ b/docs/csharp/tutorials/nullable-reference-types.md @@ -98,7 +98,7 @@ namespace NullableIntroduction } ``` -Because you didn't initialized `QuestionText`, the compiler issues a warning that a non-nullable property wasn't initialized. Your design requires the question text to be non-null, so you add a constructor to initialize it and the `QuestionType` value as well. The finished class definition looks like the following code: +Because you didn't initialize `QuestionText`, the compiler issues a warning that a non-nullable property wasn't initialized. Your design requires the question text to be non-null, so you add a constructor to initialize it and the `QuestionType` value as well. The finished class definition looks like the following code: :::code language="csharp" source="./snippets/NullableIntroduction/SurveyQuestion.cs":::