diff --git a/.github/workflows/snippets5000.yml b/.github/workflows/snippets5000.yml index 9031f1ab442fd..d6968c4d45824 100644 --- a/.github/workflows/snippets5000.yml +++ b/.github/workflows/snippets5000.yml @@ -14,8 +14,8 @@ on: default: 'Manual run' env: - DOTNET_VERSION: '9.0.*' - DOTNET_QUALITY: 'ga' + DOTNET_VERSION: '10.0.*' + DOTNET_QUALITY: 'preview' DOTNET_DO_INSTALL: 'true' # To install a version of .NET not provided by the runner, set to true EnableNuGetPackageRestore: 'True' diff --git a/.openpublishing.redirection.csharp.json b/.openpublishing.redirection.csharp.json index cd854aa2d8684..de3bf14f0c23c 100644 --- a/.openpublishing.redirection.csharp.json +++ b/.openpublishing.redirection.csharp.json @@ -778,7 +778,7 @@ }, { "source_path_from_root": "/docs/csharp/language-reference/keywords/as.md", - "redirect_url": "/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator" + "redirect_url": "/dotnet/csharp/language-reference/operators/type-testing-and-cast#the-as-operator" }, { "source_path_from_root": "/docs/csharp/language-reference/keywords/await.md", @@ -1075,7 +1075,7 @@ }, { "source_path_from_root": "/docs/csharp/language-reference/keywords/typeof.md", - "redirect_url": "/dotnet/csharp/language-reference/operators/type-testing-and-cast#typeof-operator" + "redirect_url": "/dotnet/csharp/language-reference/operators/type-testing-and-cast#the-typeof-operator" }, { "source_path_from_root": "/docs/csharp/language-reference/keywords/types.md", @@ -4282,7 +4282,7 @@ }, { "source_path_from_root": "/docs/csharp/whats-new.md", - "redirect_url": "/dotnet/csharp/whats-new/csharp-13", + "redirect_url": "/dotnet/csharp/whats-new/csharp-14", "redirect_document_id": true }, { diff --git a/docfx.json b/docfx.json index 9c2b5973f1b6a..6efaeef6ad032 100644 --- a/docfx.json +++ b/docfx.json @@ -54,7 +54,10 @@ "csharp-11.0/*.md", "csharp-12.0/*.md", "csharp-13.0/*.md", - "field-keyword.md" + "field-keyword.md", + "unbound-generic-types-in-nameof.md", + "first-class-span-types.md", + "simple-lambda-parameters-with-modifiers.md" ], "src": "_csharplang/proposals", "dest": "csharp/language-reference/proposals", @@ -504,7 +507,7 @@ "_csharplang/proposals/csharp-11.0/*.md": "09/30/2022", "_csharplang/proposals/csharp-12.0/*.md": "08/15/2023", "_csharplang/proposals/csharp-13.0/*.md": "10/31/2024", - "_csharplang/proposals/*.md": "10/31/2024", + "_csharplang/proposals/*.md": "02/14/2025", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "11/08/2022", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "11/08/2023", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "11/09/2024", @@ -680,6 +683,9 @@ "_csharplang/proposals/csharp-13.0/partial-properties.md": "All partial properties and indexers", "_csharplang/proposals/csharp-13.0/overload-resolution-priority.md": "Overload resolution priority tiebreaker attribute", "_csharplang/proposals/field-keyword.md": "The `field` contextual keyword", + "_csharplang/proposals/unbound-generic-types-in-nameof.md": "Unbound generic types in `nameof`", + "_csharplang/proposals/first-class-span-types.md": "First-class span types", + "_csharplang/proposals/simple-lambda-parameters-with-modifiers.md": "Simple lambda parameters with modifiers", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "C# compiler breaking changes since C# 11", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "C# compiler breaking changes since C# 12", @@ -801,6 +807,9 @@ "_csharplang/proposals/csharp-13.0/partial-properties.md": "This proposal provides for partial properties and indexers, allowing the definition of a property or indexer to be split across multiple parts.", "_csharplang/proposals/csharp-13.0/overload-resolution-priority.md": "This proposal introduces a new attribute, `OverloadResolutionPriorityAttribute`, that can be applied to methods to influence overload resolution.", "_csharplang/proposals/field-keyword.md": "This proposal introduces a new keyword, `field`, that accesses the compiler generated backing field in a property accessor.", + "_csharplang/proposals/unbound-generic-types-in-nameof.md": "This proposal introduces the ability to use unbound generic types such as `List<>` in `nameof` expressions. The type argument isn't required.", + "_csharplang/proposals/first-class-span-types.md": "This proposal provides several implicit conversions to `Span` and `ReadOnlySpan` that enable library authors to have fewer overloads and developers to write code that resolves to faster Span based APIs", + "_csharplang/proposals/simple-lambda-parameters-with-modifiers.md": "This proposal provides allows lambda parmaeters to be declared with modifiers without requiring their type names. You can add modifiers like `ref` and `out` to lambda parameters without specifying their type.", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "Learn about any breaking changes since the initial release of C# 10 and included in C# 11", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 8.md": "Learn about any breaking changes since the initial release of C# 11 and included in C# 12", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 9.md": "Learn about any breaking changes since the initial release of C# 12 and included in C# 13", diff --git a/docs/csharp/fundamentals/tutorials/safely-cast-using-pattern-matching-is-and-as-operators.md b/docs/csharp/fundamentals/tutorials/safely-cast-using-pattern-matching-is-and-as-operators.md index ccfac9b081586..3ca501163156e 100644 --- a/docs/csharp/fundamentals/tutorials/safely-cast-using-pattern-matching-is-and-as-operators.md +++ b/docs/csharp/fundamentals/tutorials/safely-cast-using-pattern-matching-is-and-as-operators.md @@ -9,13 +9,13 @@ helpviewer_keywords: --- # How to safely cast by using pattern matching and the is and as operators -Because objects are polymorphic, it's possible for a variable of a base class type to hold a derived [type](../types/index.md). To access the derived type's instance members, it's necessary to [cast](../../programming-guide/types/casting-and-type-conversions.md) the value back to the derived type. However, a cast creates the risk of throwing an . C# provides [pattern matching](../functional/pattern-matching.md) statements that perform a cast conditionally only when it will succeed. C# also provides the [is](../../language-reference/operators/type-testing-and-cast.md#is-operator) and [as](../../language-reference/operators/type-testing-and-cast.md#as-operator) operators to test if a value is of a certain type. +Because objects are polymorphic, it's possible for a variable of a base class type to hold a derived [type](../types/index.md). To access the derived type's instance members, it's necessary to [cast](../../programming-guide/types/casting-and-type-conversions.md) the value back to the derived type. However, a cast creates the risk of throwing an . C# provides [pattern matching](../functional/pattern-matching.md) statements that perform a cast conditionally only when it will succeed. C# also provides the [is](../../language-reference/operators/type-testing-and-cast.md#the-is-operator) and [as](../../language-reference/operators/type-testing-and-cast.md#the-as-operator) operators to test if a value is of a certain type. The following example shows how to use the pattern matching `is` statement: :::code language="csharp" source="./snippets/safelycast/patternmatching/Program.cs" ID="PatternMatchingIs"::: -The preceding sample demonstrates a few features of pattern matching syntax. The `if (a is Mammal m)` statement combines the test with an initialization assignment. The assignment occurs only when the test succeeds. The variable `m` is only in scope in the embedded `if` statement where it has been assigned. You can't access `m` later in the same method. The preceding example also shows how to use the [`as` operator](../../language-reference/operators/type-testing-and-cast.md#as-operator) to convert an object to a specified type. +The preceding sample demonstrates a few features of pattern matching syntax. The `if (a is Mammal m)` statement combines the test with an initialization assignment. The assignment occurs only when the test succeeds. The variable `m` is only in scope in the embedded `if` statement where it has been assigned. You can't access `m` later in the same method. The preceding example also shows how to use the [`as` operator](../../language-reference/operators/type-testing-and-cast.md#the-as-operator) to convert an object to a specified type. You can also use the same syntax for testing if a [nullable value type](../../language-reference/builtin-types/nullable-value-types.md) has a value, as shown in the following example: diff --git a/docs/csharp/index.yml b/docs/csharp/index.yml index 35a03bc5ae2f8..fbb14a2414588 100644 --- a/docs/csharp/index.yml +++ b/docs/csharp/index.yml @@ -32,7 +32,7 @@ highlightedContent: # Card - title: What's new itemType: whats-new - url: ./whats-new/csharp-13.md + url: ./whats-new/csharp-14.md # Card - title: Learn C# video series itemType: video diff --git a/docs/csharp/language-reference/builtin-types/built-in-types.md b/docs/csharp/language-reference/builtin-types/built-in-types.md index fb4a853afb971..e5909143f9683 100644 --- a/docs/csharp/language-reference/builtin-types/built-in-types.md +++ b/docs/csharp/language-reference/builtin-types/built-in-types.md @@ -1,7 +1,7 @@ --- title: "Built-in types" description: "Learn C# built-in value and reference types" -ms.date: 03/15/2021 +ms.date: 02/19/2025 helpviewer_keywords: - "types [C#], built-in" - "built-in C# types" @@ -36,7 +36,7 @@ The following table lists the C# built-in [reference](../keywords/reference-type |[`string`](reference-types.md#the-string-type)|| |[`dynamic`](reference-types.md#the-dynamic-type)|| -In the preceding tables, each C# type keyword from the left column (except [dynamic](reference-types.md#the-dynamic-type)) is an alias for the corresponding .NET type. They are interchangeable. For example, the following declarations declare variables of the same type: +In the preceding tables, each C# type keyword from the left column (except [dynamic](reference-types.md#the-dynamic-type)) is an alias for the corresponding .NET type. They're interchangeable. For example, the following declarations declare variables of the same type: ```csharp int a = 123; @@ -45,6 +45,16 @@ System.Int32 b = 123; The [`void`](void.md) keyword represents the absence of a type. You use it as the return type of a method that doesn't return a value. +The C# language includes specialized rules for the and types. These types aren't classified as built-in types, because there aren't C# keywords that correspond to these types. The C# language defines implicit conversions from array types and the string type to `Span` and `ReadOnlySpan`. These conversions integrate `Span` types into more natural programming scenarios. The following conversions are defined as *implicit span conversions*: + +- From any single-dimensional array with element type `E` to `System.Span` +- From any single-dimensional array with element type `E` to `System.ReadOnlySpan`, when `E` has covariance conversion or an identity conversion to `U` +- From `System.Span` to `System.ReadOnlySpan`, when `E` has a covariance conversion or an identity conversion to `U` +- From `System.ReadOnlySpan` to `System.ReadOnlySpan`, when `E` has a covariance conversion or an identity conversion to `U` +- From `string` to `System.ReadOnlySpan` + +The compiler never ignores any user defined conversion where an applicable *implicit span conversion* exists. Implicit span conversions can be applied to the first argument of [extension methods](../../programming-guide/classes-and-structs/extension-methods.md), the parameter with the `this` modifier. Implicit span conversions aren't considered for method group conversions. + ## See also - [Use language keywords instead of framework type names (style rule IDE0049)](../../../fundamentals/code-analysis/style-rules/ide0049.md) diff --git a/docs/csharp/language-reference/builtin-types/collections.md b/docs/csharp/language-reference/builtin-types/collections.md index 4fe64a2a2f5b3..b191306fa76f4 100644 --- a/docs/csharp/language-reference/builtin-types/collections.md +++ b/docs/csharp/language-reference/builtin-types/collections.md @@ -1,11 +1,11 @@ --- title: "Collections" description: Learn about collections in C#, which are used to work with groups of objects. Collections have different characteristics regarding adding and removing elements, modifying elements, and enumerating the collection elements. -ms.date: 08/22/2023 +ms.date: 02/04/2025 --- # Collections -The .NET runtime provides many collection types that store and manage groups of related objects. Some of the collection types, such as , , and are recognized in the C# language. In addition, interfaces like are recognized in the language for enumerating the elements of a collection. +The .NET runtime provides many collection types that store and manage groups of related objects. Some of the collection types, such as , , and are recognized [in the C# language](./built-in-types.md). In addition, interfaces like are recognized in the language for enumerating the elements of a collection. Collections provide a flexible way to work with groups of objects. You can classify different collections by these characteristics: diff --git a/docs/csharp/language-reference/builtin-types/nullable-value-types.md b/docs/csharp/language-reference/builtin-types/nullable-value-types.md index 323eff25986ff..b5feac649fd2f 100644 --- a/docs/csharp/language-reference/builtin-types/nullable-value-types.md +++ b/docs/csharp/language-reference/builtin-types/nullable-value-types.md @@ -96,17 +96,17 @@ The following example shows how to determine whether a instance. +As the example shows, you use the [typeof](../operators/type-testing-and-cast.md#the-typeof-operator) operator to create a instance. If you want to determine whether an instance is of a nullable value type, don't use the method to get a instance to be tested with the preceding code. When you call the method on an instance of a nullable value type, the instance is [boxed](#boxing-and-unboxing) to . As boxing of a non-null instance of a nullable value type is equivalent to boxing of a value of the underlying type, returns a instance that represents the underlying type of a nullable value type: [!code-csharp-interactive[GetType example](snippets/shared/NullableValueTypes.cs#GetType)] -Also, don't use the [is](../operators/type-testing-and-cast.md#is-operator) operator to determine whether an instance is of a nullable value type. As the following example shows, you cannot distinguish types of a nullable value type instance and its underlying type instance with the `is` operator: +Also, don't use the [is](../operators/type-testing-and-cast.md#the-is-operator) operator to determine whether an instance is of a nullable value type. As the following example shows, you cannot distinguish types of a nullable value type instance and its underlying type instance with the `is` operator: [!code-csharp-interactive[is operator example](snippets/shared/NullableValueTypes.cs#IsOperator)] -Instead use the from the first example and [typeof](../operators/type-testing-and-cast.md#typeof-operator) operator to check if an instance is of a nullable value type. +Instead use the from the first example and [typeof](../operators/type-testing-and-cast.md#the-typeof-operator) operator to check if an instance is of a nullable value type. > [!NOTE] > The methods described in this section are not applicable in the case of [nullable reference types](nullable-reference-types.md). diff --git a/docs/csharp/language-reference/compiler-messages/assembly-references.md b/docs/csharp/language-reference/compiler-messages/assembly-references.md index 6461228fc8794..a19067f8af1c0 100644 --- a/docs/csharp/language-reference/compiler-messages/assembly-references.md +++ b/docs/csharp/language-reference/compiler-messages/assembly-references.md @@ -81,7 +81,7 @@ These compiler errors indicate one of these problems in your code: - The project doesn't reference the required assembly. To fix this error, [add a reference to the required assembly](../../../standard/assembly/index.md#add-a-reference-to-an-assembly). - You misspelled the name of a type. Check the name of the type. -- You used a variable name where the name of a was expected, such as in the [`typeof` operator](../operators/type-testing-and-cast.md#typeof-operator) or the [`is` operator](../operators/type-testing-and-cast.md#is-operator). +- You used a variable name where the name of a was expected, such as in the [`typeof` operator](../operators/type-testing-and-cast.md#the-typeof-operator) or the [`is` operator](../operators/type-testing-and-cast.md#the-is-operator). - You used the [global scope operator, (`::`)](../operators/namespace-alias-qualifier.md) when the type isn't in the global namespace. ## Type forwarding diff --git a/docs/csharp/language-reference/compiler-messages/cs0039.md b/docs/csharp/language-reference/compiler-messages/cs0039.md index cf168926849de..6ce49e440313b 100644 --- a/docs/csharp/language-reference/compiler-messages/cs0039.md +++ b/docs/csharp/language-reference/compiler-messages/cs0039.md @@ -12,7 +12,7 @@ ms.assetid: f9fcb1c5-4ea4-41f3-826e-9ab0ac43dd3e Cannot convert type 'type1' to 'type2' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion -A conversion with the [as](../operators/type-testing-and-cast.md#as-operator) operator is allowed by inheritance, reference conversions, and boxing conversions. +A conversion with the [as](../operators/type-testing-and-cast.md#the-as-operator) operator is allowed by inheritance, reference conversions, and boxing conversions. ## Example diff --git a/docs/csharp/language-reference/compiler-messages/cs0413.md b/docs/csharp/language-reference/compiler-messages/cs0413.md index 59e47582fa75d..0896efebfcc21 100644 --- a/docs/csharp/language-reference/compiler-messages/cs0413.md +++ b/docs/csharp/language-reference/compiler-messages/cs0413.md @@ -12,7 +12,7 @@ ms.assetid: a01bd1ec-015b-433b-be55-b91db268d6a5 The type parameter 'type parameter' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint -This error occurs if a generic type uses the [as](../operators/type-testing-and-cast.md#as-operator) operator, but that generic type does not have a class type constraint. The `as` operator is only allowed with reference and nullable value types, so the type parameter must be constrained to guarantee that it is not a value type. To avoid this error, use a class type constraint or a reference type constraint. +This error occurs if a generic type uses the [as](../operators/type-testing-and-cast.md#the-as-operator) operator, but that generic type does not have a class type constraint. The `as` operator is only allowed with reference and nullable value types, so the type parameter must be constrained to guarantee that it is not a value type. To avoid this error, use a class type constraint or a reference type constraint. This is because the `as` operator could return `null`, which is not a possible value for a value type, and the type parameter must be treated as a value type unless it is a class type constraint or a reference type constraint. diff --git a/docs/csharp/language-reference/compiler-messages/params-arrays.md b/docs/csharp/language-reference/compiler-messages/params-arrays.md index c753fe410eec6..16699e1dd080b 100644 --- a/docs/csharp/language-reference/compiler-messages/params-arrays.md +++ b/docs/csharp/language-reference/compiler-messages/params-arrays.md @@ -17,6 +17,7 @@ f1_keywords: - "CS9225" - "CS9227" - "CS9228" + - "CS9272" helpviewer_keywords: - "CS0225" - "CS0231" @@ -33,7 +34,8 @@ helpviewer_keywords: - "CS9225" - "CS9227" - "CS9228" -ms.date: 05/20/2024 + - "CS9272" +ms.date: 02/13/2025 --- # Errors and warnings related to the `params` modifier on method parameters @@ -57,6 +59,7 @@ That's by design. The text closely matches the text of the compiler error / warn - [**CS9225**](#other-params-errors): *Constructor leaves required member uninitialized.* - [**CS9227**](#parameter-and-argument-type-rules): *Type does not contain a definition for a suitable instance `Add` method.* - [**CS9228**](#parameter-and-argument-type-rules): *Non-array params collection type must have an applicable constructor that can be called with no arguments.* +- [**CS9272**](#other-params-errors): *Implicitly typed lambda parameter cannot have the 'params' modifier.* ## Method declaration rules @@ -101,6 +104,7 @@ The following errors indicate other issues with using the `params` modifier: - **CS9223**: *Creation of params collection results in an infinite chain of invocation of constructor.* - **CS9224**: *Method cannot be less visible than the member with params collection.* - **CS9225**: *Constructor leaves required member uninitialized.* +- **CS9272**: *Implicitly typed lambda parameter cannot have the 'params' modifier.* A method that implements an interface must include the `params` modifier if and only if the interface member has the `params` modifier. Similarly, either both declarations of a `partial` method must include the `params` modifier, or none can include the `params` modifier. @@ -111,6 +115,7 @@ The compiler generates one of the final three errors in the preceding list when - The compiler emits **CS9223** when the code emitted to create the collection also contains a params collection of the same type. Typically, the `Add` method takes a `params` collection of the same type. - The compiler emits **CS9224** when the `Create` method for the collection type is less accessible than the method that takes the `params` parameter of the collection type. - The compiler emits **CS9225** when the collection type has a required member and the parameterless constructor doesn't initialize that member and have the on the parameterless constructor. +- The compiler emits **CS9272** when you've used the `params` modifier without type information on a lambda expression. You must specify the types for all lambda expression parameters to use the `params` modifier. ## See also diff --git a/docs/csharp/language-reference/configure-language-version.md b/docs/csharp/language-reference/configure-language-version.md index 6bf5faee80508..ee293fc8b6779 100644 --- a/docs/csharp/language-reference/configure-language-version.md +++ b/docs/csharp/language-reference/configure-language-version.md @@ -2,7 +2,7 @@ title: Configure language version description: Learn how to override the default C# language version manually. The C# compiler can support any language version up to the version in the installed SDK. ms.custom: "updateeachrelease" -ms.date: 09/17/2024 +ms.date: 01/31/2025 --- # Configure C# language version @@ -17,7 +17,7 @@ If you need a specific language version that differs from the one automatically > [!WARNING] > -> Setting the `LangVersion` element to `latest` is discouraged. The `latest` setting means the installed compiler uses its latest version. That can change from machine to machine, making builds unreliable. In addition, it enables language features that may require runtime or library features not included in the current SDK. +> Setting the `LangVersion` element to `latest` is discouraged. The `latest` setting means the installed compiler uses its latest version. The value of `latest` can change from machine to machine, making builds unreliable. In addition, it enables language features that might require runtime or library features not included in the current SDK. If you must specify your C# version explicitly, you can do so in several ways: @@ -28,11 +28,11 @@ If you must specify your C# version explicitly, you can do so in several ways: > [!TIP] > You can see the language version in Visual Studio in the project properties page. Under the *Build* tab, the *Advanced* pane displays the version selected. > -> To know what language version you're currently using, put `#error version` (case sensitive) in your code. This makes the compiler report a compiler error, CS8304, with a message containing the compiler version being used and the current selected language version. For more information about this pragma, see [#error (C# Reference)](preprocessor-directives.md#error-and-warning-information). +> To know what language version you're currently using, put `#error version` (case sensitive) in your code. This pragma makes the compiler report a compiler error, CS8304, with a message containing the compiler version and the current selected language version. For more information about this pragma, see [#error (C# Reference)](preprocessor-directives.md#error-and-warning-information). ## Edit the project file -You can set the language version in your project file. For example, if you explicitly want access to preview features, add an element like this: +You can set the language version in your project file. For example, if you explicitly want access to preview features, add an element like the following example: ```xml @@ -40,7 +40,7 @@ You can set the language version in your project file. For example, if you expli ``` -The value `preview` uses the latest available preview C# language version that your compiler supports. +The value `preview` uses the latest available preview C# language version your compiler supports. ## Configure multiple projects @@ -58,7 +58,7 @@ Builds in all subdirectories of the directory containing that file now use the p > [!NOTE] > -> The versions for C# and VB are different. Don't use the *Directory.Build.Props* file for a folder where subdirectories contain projects for both languages. The versions won't match. +> The versions for C# and VB are different. Don't use the *Directory.Build.Props* file for a folder where subdirectories contain projects for both languages. The versions don't match. ## C# language version reference diff --git a/docs/csharp/language-reference/includes/default-langversion-table.md b/docs/csharp/language-reference/includes/default-langversion-table.md index 276aa3b40976e..f9185ba55aa01 100644 --- a/docs/csharp/language-reference/includes/default-langversion-table.md +++ b/docs/csharp/language-reference/includes/default-langversion-table.md @@ -4,6 +4,7 @@ ms.custom: "updateeachrelease" | Target | Version | C# language version default | |------------------|---------|-----------------------------| +| .NET | 10.x | C# 14 | | .NET | 9.x | C# 13 | | .NET | 8.x | C# 12 | | .NET | 7.x | C# 11 | diff --git a/docs/csharp/language-reference/includes/langversion-table.md b/docs/csharp/language-reference/includes/langversion-table.md index 051696f4a1be5..d7d81b3b80f23 100644 --- a/docs/csharp/language-reference/includes/langversion-table.md +++ b/docs/csharp/language-reference/includes/langversion-table.md @@ -7,6 +7,7 @@ ms.custom: "updateeachrelease" | `preview` | The compiler accepts all valid language syntax from the latest preview version. | | `latest` | The compiler accepts syntax from the latest released version of the compiler (including minor version). | | `latestMajor`
or `default` | The compiler accepts syntax from the latest released major version of the compiler. | +| `14.0` | The compiler accepts only syntax that is included in C# 14 or lower. | | `13.0` | The compiler accepts only syntax that is included in C# 13 or lower. | | `12.0` | The compiler accepts only syntax that is included in C# 12 or lower. | | `11.0` | The compiler accepts only syntax that is included in C# 11 or lower. | diff --git a/docs/csharp/language-reference/keywords/index.md b/docs/csharp/language-reference/keywords/index.md index 4f7d06539e43f..8cd1a66953ff2 100644 --- a/docs/csharp/language-reference/keywords/index.md +++ b/docs/csharp/language-reference/keywords/index.md @@ -20,7 +20,7 @@ The first table in this article lists keywords that are reserved identifiers in :::row::: :::column::: [`abstract`](abstract.md) - [`as`](../operators/type-testing-and-cast.md#as-operator) + [`as`](../operators/type-testing-and-cast.md#the-as-operator) [`base`](base.md) [`bool`](../builtin-types/bool.md) [`break`](../statements/jump-statements.md#the-break-statement) @@ -91,7 +91,7 @@ The first table in this article lists keywords that are reserved identifiers in [`throw`](../statements/exception-handling-statements.md#the-throw-statement) [`true`](../builtin-types/bool.md) [`try`](../statements/exception-handling-statements.md#the-try-statement) - [`typeof`](../operators/type-testing-and-cast.md#typeof-operator) + [`typeof`](../operators/type-testing-and-cast.md#the-typeof-operator) [`uint`](../builtin-types/integral-numeric-types.md) [`ulong`](../builtin-types/integral-numeric-types.md) [`unchecked`](../statements/checked-and-unchecked.md) diff --git a/docs/csharp/language-reference/operators/index.md b/docs/csharp/language-reference/operators/index.md index b4f36f0695dfc..3b83d5cf12849 100644 --- a/docs/csharp/language-reference/operators/index.md +++ b/docs/csharp/language-reference/operators/index.md @@ -70,14 +70,14 @@ The following table lists the C# operators starting with the highest precedence | Operators | Category or name | | --------- | ---------------- | -| [x.y](member-access-operators.md#member-access-expression-), [f(x)](member-access-operators.md#invocation-expression-), [a[i]](member-access-operators.md#indexer-operator-), [`x?.y`](member-access-operators.md#null-conditional-operators--and-), [`x?[y]`](member-access-operators.md#null-conditional-operators--and-), [x++](arithmetic-operators.md#increment-operator-), [x--](arithmetic-operators.md#decrement-operator---), [x!](null-forgiving.md), [new](new-operator.md), [typeof](type-testing-and-cast.md#typeof-operator), [checked](../statements/checked-and-unchecked.md), [unchecked](../statements/checked-and-unchecked.md), [default](default.md), [nameof](nameof.md), [delegate](delegate-operator.md), [sizeof](sizeof.md), [stackalloc](stackalloc.md), [x->y](pointer-related-operators.md#pointer-member-access-operator--) | Primary | +| [x.y](member-access-operators.md#member-access-expression-), [f(x)](member-access-operators.md#invocation-expression-), [a[i]](member-access-operators.md#indexer-operator-), [`x?.y`](member-access-operators.md#null-conditional-operators--and-), [`x?[y]`](member-access-operators.md#null-conditional-operators--and-), [x++](arithmetic-operators.md#increment-operator-), [x--](arithmetic-operators.md#decrement-operator---), [x!](null-forgiving.md), [new](new-operator.md), [typeof](type-testing-and-cast.md#the-typeof-operator), [checked](../statements/checked-and-unchecked.md), [unchecked](../statements/checked-and-unchecked.md), [default](default.md), [nameof](nameof.md), [delegate](delegate-operator.md), [sizeof](sizeof.md), [stackalloc](stackalloc.md), [x->y](pointer-related-operators.md#pointer-member-access-operator--) | Primary | | [+x](arithmetic-operators.md#unary-plus-and-minus-operators), [-x](arithmetic-operators.md#unary-plus-and-minus-operators), [\!x](boolean-logical-operators.md#logical-negation-operator-), [~x](bitwise-and-shift-operators.md#bitwise-complement-operator-), [++x](arithmetic-operators.md#increment-operator-), [--x](arithmetic-operators.md#decrement-operator---), [^x](member-access-operators.md#index-from-end-operator-), [(T)x](type-testing-and-cast.md#cast-expression), [await](await.md), [&x](pointer-related-operators.md#address-of-operator-), [*x](pointer-related-operators.md#pointer-indirection-operator-), [true and false](true-false-operators.md) | Unary | | [x..y](member-access-operators.md#range-operator-) | Range | | [switch](switch-expression.md), [with](with-expression.md) | `switch` and `with` expressions | | [x * y](arithmetic-operators.md#multiplication-operator-), [x / y](arithmetic-operators.md#division-operator-), [x % y](arithmetic-operators.md#remainder-operator-) | Multiplicative| | [x + y](arithmetic-operators.md#addition-operator-), [x – y](arithmetic-operators.md#subtraction-operator--) | Additive | | [x \<\< y](bitwise-and-shift-operators.md#left-shift-operator-), [x >> y](bitwise-and-shift-operators.md#right-shift-operator-), [x >>> y](bitwise-and-shift-operators.md#unsigned-right-shift-operator-) | Shift | -| [x \< y](comparison-operators.md#less-than-operator-), [x > y](comparison-operators.md#greater-than-operator-), [x \<= y](comparison-operators.md#less-than-or-equal-operator-), [x >= y](comparison-operators.md#greater-than-or-equal-operator-), [is](type-testing-and-cast.md#is-operator), [as](type-testing-and-cast.md#as-operator) | Relational and type-testing | +| [x \< y](comparison-operators.md#less-than-operator-), [x > y](comparison-operators.md#greater-than-operator-), [x \<= y](comparison-operators.md#less-than-or-equal-operator-), [x >= y](comparison-operators.md#greater-than-or-equal-operator-), [is](type-testing-and-cast.md#the-is-operator), [as](type-testing-and-cast.md#the-as-operator) | Relational and type-testing | | [x == y](equality-operators.md#equality-operator-), [x != y](equality-operators.md#inequality-operator-) | Equality | | `x & y` | [Boolean logical AND](boolean-logical-operators.md#logical-and-operator-) or [bitwise logical AND](bitwise-and-shift-operators.md#logical-and-operator-) | | `x ^ y` | [Boolean logical XOR](boolean-logical-operators.md#logical-exclusive-or-operator-) or [bitwise logical XOR](bitwise-and-shift-operators.md#logical-exclusive-or-operator-) | diff --git a/docs/csharp/language-reference/operators/is.md b/docs/csharp/language-reference/operators/is.md index 8bf9a7dc44b7a..9b711ddeae71f 100644 --- a/docs/csharp/language-reference/operators/is.md +++ b/docs/csharp/language-reference/operators/is.md @@ -10,7 +10,7 @@ helpviewer_keywords: --- # The `is` operator (C# reference) -The `is` operator checks if the result of an expression is compatible with a given type. For information about the type-testing `is` operator, see the [is operator](type-testing-and-cast.md#is-operator) section of the [Type-testing and cast operators](type-testing-and-cast.md) article. You can also use the `is` operator to match an expression against a pattern, as the following example shows: +The `is` operator checks if the result of an expression is compatible with a given type. For information about the type-testing `is` operator, see the [is operator](type-testing-and-cast.md#the-is-operator) section of the [Type-testing and cast operators](type-testing-and-cast.md) article. You can also use the `is` operator to match an expression against a pattern, as the following example shows: :::code language="csharp" source="snippets/shared/IsOperator.cs" id="IntroExample"::: diff --git a/docs/csharp/language-reference/operators/lambda-expressions.md b/docs/csharp/language-reference/operators/lambda-expressions.md index f40bd119af835..6db9572f279e6 100644 --- a/docs/csharp/language-reference/operators/lambda-expressions.md +++ b/docs/csharp/language-reference/operators/lambda-expressions.md @@ -1,7 +1,7 @@ --- title: "Lambda expressions - Lambda expressions and anonymous functions" description: C# lambda expressions that are used to create anonymous functions and expression bodied members. -ms.date: 11/22/2024 +ms.date: 02/19/2025 helpviewer_keywords: - "lambda expressions [C#]" - "outer variables [C#]" @@ -49,7 +49,7 @@ A lambda expression with an expression on the right side of the `=>` operator is (input-parameters) => expression ``` -The body of an expression lambda can consist of a method call. However, if you're creating [expression trees](../../advanced-topics/expression-trees/index.md) that are evaluated outside the context of the .NET Common Language Runtime (CLR), such as in SQL Server, you shouldn't use method calls in lambda expressions. The methods have no meaning outside the context of the .NET Common Language Runtime (CLR). +The body of an expression lambda can consist of a method call. However, when creating [expression trees](../../advanced-topics/expression-trees/index.md) evaluated by a query provider, limit method calls to those methods recognized by the query provider. Otherwise, the query provider can't replicate the method's function. ## Statement lambdas @@ -79,11 +79,11 @@ Two or more input parameters are separated by commas: :::code language="csharp" source="snippets/lambda-expressions/GeneralExamples.cs" id="SnippetTwoParameters"::: -Sometimes the compiler can't infer the types of input parameters. You can specify the types explicitly as shown in the following example: +The compiler typically infers the types for parameters to lambda expressions, referred to as an *implicitly typed parameter list*. You can specify the types explicitly, referred to as an *explicitly typed parameter list*. An explicitly typed parameter list is shown in the following example. : :::code language="csharp" source="snippets/lambda-expressions/GeneralExamples.cs" id="SnippetExplicitlyTypedParameters"::: -Input parameter types must be all explicit or all implicit; otherwise, a [CS0748](../compiler-messages/lambda-expression-errors.md#lambda-expression-parameters-and-returns) compiler error occurs. +Input parameter types must be all explicit or all implicit; otherwise, a [CS0748](../compiler-messages/lambda-expression-errors.md#lambda-expression-parameters-and-returns) compiler error occurs. Before C# 14, you must include the explicit type on a parameter if it has any modifiers, such as `ref` or `out`. In C# 14, that restriction is removed. However, you must still declare the type if you use the `params` modifier. You can use [discards](../../fundamentals/functional/discards.md) to specify two or more input parameters of a lambda expression that aren't used in the expression: @@ -92,13 +92,13 @@ You can use [discards](../../fundamentals/functional/discards.md) to specify two Lambda discard parameters can be useful when you use a lambda expression to [provide an event handler](../../programming-guide/events/how-to-subscribe-to-and-unsubscribe-from-events.md). > [!NOTE] -> For backwards compatibility, if only a single input parameter is named `_`, then, within a lambda expression, `_` is treated as the name of that parameter. +> For backwards compatibility, if only a single input parameter is named `_`, `_` is treated as the name of that parameter within that lambda expression. -Beginning with C# 12, you can provide *default values* for parameters on lambda expressions. The syntax and the restrictions on default parameter values are the same as for methods and local functions. The following example declares a lambda expression with a default parameter, then calls it once using the default and once with two explicit parameters: +Beginning with C# 12, you can provide *default values* for explicitly typed parameter lists. The syntax and the restrictions on default parameter values are the same as for methods and local functions. The following example declares a lambda expression with a default parameter, then calls it once using the default and once with two explicit parameters: :::code language="csharp" source="snippets/lambda-expressions/GeneralExamples.cs" id="SnippetDefaultParameters"::: -You can also declare lambda expressions with `params` arrays or collections as parameters: +You can also declare lambda expressions with `params` arrays or collections as the last parameter in an explicitly typed parameter list: :::code language="csharp" source="snippets/lambda-expressions/GeneralExamples.cs" id="SnippetParamsArray"::: @@ -166,7 +166,7 @@ For more information about how to create and use async methods, see [Asynchronou ## Lambda expressions and tuples -The C# language provides built-in support for [tuples](../builtin-types/value-tuples.md). You can provide a tuple as an argument to a lambda expression, and your lambda expression can also return a tuple. In some cases, the C# compiler uses type inference to determine the types of tuple components. +The C# language provides built-in support for [tuples](../builtin-types/value-tuples.md). You can provide a tuple as an argument to a lambda expression, and your lambda expression can also return a tuple. In some cases, the C# compiler uses type inference to determine the types of tuple elements. You define a tuple by enclosing a comma-delimited list of its components in parentheses. The following example uses tuple with three components to pass a sequence of numbers to a lambda expression, which doubles each value and returns a tuple with three components that contains the result of the multiplications. @@ -299,7 +299,7 @@ var inc = [return: NotNullIfNotNull(nameof(s))] (int? s) => s.HasValue ? s++ : n As the preceding examples show, you must parenthesize the input parameters when you add attributes to a lambda expression or its parameters. > [!IMPORTANT] -> Lambda expressions are invoked through the underlying delegate type. That is different than methods and local functions. The delegate's `Invoke` method doesn't check attributes on the lambda expression. Attributes don't have any effect when the lambda expression is invoked. Attributes on lambda expressions are useful for code analysis, and can be discovered via reflection. One consequence of this decision is that the cannot be applied to a lambda expression. +> Lambda expressions are invoked through the underlying delegate type. That invocation is different than methods and local functions. The delegate's `Invoke` method doesn't check attributes on the lambda expression. Attributes don't have any effect when the lambda expression is invoked. Attributes on lambda expressions are useful for code analysis, and can be discovered via reflection. One consequence of this decision is that the can't be applied to a lambda expression. ## Capture of outer variables and variable scope in lambda expressions @@ -309,7 +309,7 @@ Lambdas can refer to *outer variables*. These *outer variables* are the variable The following rules apply to variable scope in lambda expressions: -- A variable that is captured won't be garbage-collected until the delegate that references it becomes eligible for garbage collection. +- A variable that is captured isn't garbage-collected until the delegate that references it becomes eligible for garbage collection. - Variables introduced within a lambda expression aren't visible in the enclosing method. - A lambda expression can't directly capture an [in](../keywords/method-parameters.md#in-parameter-modifier), [ref](../keywords/ref.md), or [out](../keywords/method-parameters.md#out-parameter-modifier) parameter from the enclosing method. - A [return](../statements/jump-statements.md#the-return-statement) statement in a lambda expression doesn't cause the enclosing method to return. diff --git a/docs/csharp/language-reference/operators/lambda-operator.md b/docs/csharp/language-reference/operators/lambda-operator.md index e32081e7a99aa..35de576ebcf01 100644 --- a/docs/csharp/language-reference/operators/lambda-operator.md +++ b/docs/csharp/language-reference/operators/lambda-operator.md @@ -1,7 +1,7 @@ --- title: "The lambda operator - The `=>` operator is used to define a lambda expression" description: "The C# => operator defines lambda expressions and expression bodied members. Lambda expressions define a block of code used as data." -ms.date: 11/28/2022 +ms.date: 02/19/2025 f1_keywords: - "=>_CSharpKeyword" helpviewer_keywords: @@ -19,15 +19,15 @@ In [lambda expressions](lambda-expressions.md), the lambda operator `=>` separat The following example uses the [LINQ](/dotnet/csharp/linq/) feature with method syntax to demonstrate the usage of lambda expressions: -[!code-csharp-interactive[infer types of input variables](snippets/shared/LambdaOperator.cs#InferredTypes)] +:::code language="csharp" interactive="try-dotnet-method" source="snippets/shared/LambdaOperator.cs" id="InferredTypes"::: -Input parameters of a lambda expression are strongly typed at compile time. When the compiler can infer the types of input parameters, like in the preceding example, you may omit type declarations. If you need to specify the type of input parameters, you must do that for each parameter, as the following example shows: +Input parameters of a lambda expression are strongly typed at compile time. When the compiler can infer the types of input parameters, like in the preceding example, you can omit type declarations. If you need to specify the type of input parameters, you must do that for each parameter, as the following example shows: -[!code-csharp-interactive[specify types of input variables](snippets/shared/LambdaOperator.cs#ExplicitTypes)] +:::code language="csharp" interactive="try-dotnet-method" source="snippets/shared/LambdaOperator.cs" id="ExplicitTypes"::: The following example shows how to define a lambda expression without input parameters: -[!code-csharp-interactive[without input variables](snippets/shared/LambdaOperator.cs#WithoutInput)] +:::code language="csharp" interactive="try-dotnet-method" source="snippets/shared/LambdaOperator.cs" id="WithoutInput"::: For more information, see [Lambda expressions](lambda-expressions.md). @@ -39,7 +39,7 @@ An expression body definition has the following general syntax: member => expression; ``` -where `expression` is a valid expression. The return type of `expression` must be implicitly convertible to the member's return type. If the member: +Where `expression` is a valid expression. The return type of `expression` must be implicitly convertible to the member's return type. If the member: - Has a `void` return type or - Is a: diff --git a/docs/csharp/language-reference/operators/nameof.md b/docs/csharp/language-reference/operators/nameof.md index 8773cbccee0b9..1b1f2214b8201 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: 11/28/2022 +ms.date: 02/19/2025 f1_keywords: - "nameof_CSharpKeyword" - "nameof" @@ -14,11 +14,11 @@ helpviewer_keywords: A `nameof` expression produces the name of a variable, type, or member as the string constant. A `nameof` expression is evaluated at compile time and has no effect at run time. When the operand is a type or a namespace, the produced name isn't [fully qualified](~/_csharpstandard/standard/basic-concepts.md#783-fully-qualified-names). The following example shows the use of a `nameof` expression: -[!code-csharp-interactive[nameof expression](snippets/shared/NameOfOperator.cs#Examples)] +:::code language="csharp" interactive="try-dotnet-method" source="snippets/shared/NameOfOperator.cs" id="Examples"::: -You can use a `nameof` expression to make the argument-checking code more maintainable: +The preceding example using `List<>` is supported in C# 14 and later. You can use a `nameof` expression to make the argument-checking code more maintainable: -[!code-csharp[nameof and argument check](snippets/shared/NameOfOperator.cs#ExceptionMessage)] +:::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: @@ -28,7 +28,7 @@ A `nameof` expression with a parameter is useful when you use the [nullable anal When the operand is a [verbatim identifier](../tokens/verbatim.md), the `@` character isn't part of the name, as the following example shows: -[!code-csharp-interactive[nameof verbatim](snippets/shared/NameOfOperator.cs#Verbatim)] +:::code language="csharp" interactive="try-dotnet-method" source="snippets/shared/NameOfOperator.cs" id="Verbatim"::: ## C# language specification diff --git a/docs/csharp/language-reference/operators/operator-overloading.md b/docs/csharp/language-reference/operators/operator-overloading.md index c61d47e5f4a02..98a9375f0cffa 100644 --- a/docs/csharp/language-reference/operators/operator-overloading.md +++ b/docs/csharp/language-reference/operators/operator-overloading.md @@ -46,7 +46,7 @@ The following table shows the operators that can't be overloaded: |[a[i]](member-access-operators.md#indexer-operator-), [`a?[i]`](member-access-operators.md#null-conditional-operators--and-)|Define an [indexer](../../programming-guide/indexers/index.md).| |[`(T)x`](type-testing-and-cast.md#cast-expression)|Define custom type conversions that can be performed by a cast expression. For more information, see [User-defined conversion operators](user-defined-conversion-operators.md).| |[`+=`](arithmetic-operators.md#compound-assignment), [`-=`](arithmetic-operators.md#compound-assignment), [`*=`](arithmetic-operators.md#compound-assignment), [`/=`](arithmetic-operators.md#compound-assignment), [`%=`](arithmetic-operators.md#compound-assignment), [`&=`](boolean-logical-operators.md#compound-assignment), [|=](boolean-logical-operators.md#compound-assignment), [`^=`](boolean-logical-operators.md#compound-assignment), [`<<=`](bitwise-and-shift-operators.md#compound-assignment), [`>>=`](bitwise-and-shift-operators.md#compound-assignment), [`>>>=`](bitwise-and-shift-operators.md#compound-assignment)|Overload the corresponding binary operator. For example, when you overload the binary `+` operator, `+=` is implicitly overloaded.| -|[`^x`](member-access-operators.md#index-from-end-operator-), [`x = y`](assignment-operator.md), [`x.y`](member-access-operators.md#member-access-expression-), [`x?.y`](member-access-operators.md#null-conditional-operators--and-), [`c ? t : f`](conditional-operator.md), [`x ?? y`](null-coalescing-operator.md), [`??= y`](null-coalescing-operator.md),
[`x..y`](member-access-operators.md#range-operator-), [`x->y`](pointer-related-operators.md#pointer-member-access-operator--), [`=>`](lambda-operator.md), [`f(x)`](member-access-operators.md#invocation-expression-), [`as`](type-testing-and-cast.md#as-operator), [`await`](await.md), [`checked`](../statements/checked-and-unchecked.md), [`unchecked`](../statements/checked-and-unchecked.md), [`default`](default.md), [`delegate`](delegate-operator.md), [`is`](type-testing-and-cast.md#is-operator), [`nameof`](nameof.md), [`new`](new-operator.md),
[`sizeof`](sizeof.md), [`stackalloc`](stackalloc.md), [`switch`](switch-expression.md), [`typeof`](type-testing-and-cast.md#typeof-operator), [`with`](with-expression.md)|None.| +|[`^x`](member-access-operators.md#index-from-end-operator-), [`x = y`](assignment-operator.md), [`x.y`](member-access-operators.md#member-access-expression-), [`x?.y`](member-access-operators.md#null-conditional-operators--and-), [`c ? t : f`](conditional-operator.md), [`x ?? y`](null-coalescing-operator.md), [`??= y`](null-coalescing-operator.md),
[`x..y`](member-access-operators.md#range-operator-), [`x->y`](pointer-related-operators.md#pointer-member-access-operator--), [`=>`](lambda-operator.md), [`f(x)`](member-access-operators.md#invocation-expression-), [`as`](type-testing-and-cast.md#the-as-operator), [`await`](await.md), [`checked`](../statements/checked-and-unchecked.md), [`unchecked`](../statements/checked-and-unchecked.md), [`default`](default.md), [`delegate`](delegate-operator.md), [`is`](type-testing-and-cast.md#the-is-operator), [`nameof`](nameof.md), [`new`](new-operator.md),
[`sizeof`](sizeof.md), [`stackalloc`](stackalloc.md), [`switch`](switch-expression.md), [`typeof`](type-testing-and-cast.md#the-typeof-operator), [`with`](with-expression.md)|None.| ## C# language specification diff --git a/docs/csharp/language-reference/operators/patterns.md b/docs/csharp/language-reference/operators/patterns.md index fc95dfde2fe6d..976b3fde1f7ec 100644 --- a/docs/csharp/language-reference/operators/patterns.md +++ b/docs/csharp/language-reference/operators/patterns.md @@ -48,15 +48,11 @@ You use declaration and type patterns to check if the run-time type of an expres 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 is `T`. - +- The type `T` is a `ref struct` type and there is 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`. 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. - - The run-time type of an expression result is a [nullable value type](../builtin-types/nullable-value-types.md) with the underlying type `T`. - - A [boxing](../../programming-guide/types/boxing-and-unboxing.md#boxing) or [unboxing](../../programming-guide/types/boxing-and-unboxing.md#unboxing) conversion exists from the run-time type of an expression result to type `T`. The following example demonstrates the last two conditions: diff --git a/docs/csharp/language-reference/operators/snippets/shared/NameOfOperator.cs b/docs/csharp/language-reference/operators/snippets/shared/NameOfOperator.cs index c7b38982b46aa..521c2603dff05 100644 --- a/docs/csharp/language-reference/operators/snippets/shared/NameOfOperator.cs +++ b/docs/csharp/language-reference/operators/snippets/shared/NameOfOperator.cs @@ -7,6 +7,7 @@ public static void Examples() // Console.WriteLine(nameof(System.Collections.Generic)); // output: Generic Console.WriteLine(nameof(List)); // output: List + Console.WriteLine(nameof(List<>)); // output: List Console.WriteLine(nameof(List.Count)); // output: Count Console.WriteLine(nameof(List.Add)); // output: Add diff --git a/docs/csharp/language-reference/operators/snippets/shared/operators.csproj b/docs/csharp/language-reference/operators/snippets/shared/operators.csproj index 73e2da4f9d7e6..281a65c5676c9 100644 --- a/docs/csharp/language-reference/operators/snippets/shared/operators.csproj +++ b/docs/csharp/language-reference/operators/snippets/shared/operators.csproj @@ -2,11 +2,12 @@ Exe - net9.0 + net10.0 enable true true 7022 + preview diff --git a/docs/csharp/language-reference/operators/type-testing-and-cast.md b/docs/csharp/language-reference/operators/type-testing-and-cast.md index 4984c47536569..e482d330918a0 100644 --- a/docs/csharp/language-reference/operators/type-testing-and-cast.md +++ b/docs/csharp/language-reference/operators/type-testing-and-cast.md @@ -1,7 +1,7 @@ --- title: "Type-testing operators and cast expressions test the runtime type of an object" description: "The `is` and `as` operators test the type of an object. The `typeof` keyword returns the type of a variable. Casts try to convert an object to a variable of a different type." -ms.date: 11/28/2022 +ms.date: 02/19/2025 author: pkulikov f1_keywords: - "is_CSharpKeyword" @@ -21,11 +21,11 @@ helpviewer_keywords: - "() operator [C#]" - "typeof operator [C#]" --- -# Type-testing operators and cast expressions - `is`, `as`, `typeof` and casts +# Type-testing operators and cast expressions - `is`, `as`, `typeof`, and casts -These operators and expressions perform type checking or type conversion. The `is` [operator](#is-operator) checks if the run-time type of an expression is compatible with a given type. The `as` [operator](#as-operator) explicitly converts an expression to a given type if its run-time type is compatible with that type. [Cast expressions](#cast-expression) perform an explicit conversion to a target type. The `typeof` [operator](#typeof-operator) obtains the instance for a type. +These operators and expressions perform type checking or type conversion. The `is` [operator](#the-is-operator) checks if the run-time type of an expression is compatible with a given type. The `as` [operator](#the-as-operator) explicitly converts an expression to a given type if its run-time type is compatible with that type. [Cast expressions](#cast-expression) perform an explicit conversion to a target type. The `typeof` [operator](#the-typeof-operator) obtains the instance for a type. -## is operator +## The `is` operator The `is` operator checks if the run-time type of an expression result is compatible with a given type. The `is` operator also tests an expression result against a pattern. @@ -35,7 +35,7 @@ The expression with the type-testing `is` operator has the following form E is T ``` -where `E` is an expression that returns a value and `T` is the name of a type or a type parameter. `E` can't be an anonymous method or a lambda expression. +Where `E` is an expression that returns a value and `T` is the name of a type or a type parameter. `E` can't be an anonymous method or a lambda expression. The `is` operator returns `true` when an expression result is non-null and any of the following conditions are true: @@ -45,17 +45,17 @@ The `is` operator returns `true` when an expression result is non-null and any o - The run-time type of an expression result is a [nullable value type](../builtin-types/nullable-value-types.md) with the underlying type `T` and the is `true`. -- A [boxing](../../programming-guide/types/boxing-and-unboxing.md#boxing) or [unboxing](../../programming-guide/types/boxing-and-unboxing.md#unboxing) conversion exists from the run-time type of an expression result to type `T`. +- A [boxing](../../programming-guide/types/boxing-and-unboxing.md#boxing) or [unboxing](../../programming-guide/types/boxing-and-unboxing.md#unboxing) conversion exists from the run-time type of an expression result to type `T` when the expression isn't an instance of a `ref struct`. -The `is` operator doesn't consider user-defined conversions. +The `is` operator doesn't consider user-defined conversions or implicit span conversions. The following example demonstrates that the `is` operator returns `true` if the run-time type of an expression result derives from a given type, that is, there exists a reference conversion between types: -[!code-csharp[is with reference conversion](snippets/shared/TypeTestingAndConversionOperators.cs#IsWithReferenceConversion)] +:::code language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="IsWithReferenceConversion"::: The next example shows that the `is` operator takes into account boxing and unboxing conversions but doesn't consider [numeric conversions](../builtin-types/numeric-conversions.md): -[!code-csharp-interactive[is with int](snippets/shared/TypeTestingAndConversionOperators.cs#IsWithInt)] +:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="IsWithInt"::: For information about C# conversions, see the [Conversions](~/_csharpstandard/standard/conversions.md) chapter of the [C# language specification](~/_csharpstandard/standard/README.md). @@ -63,11 +63,11 @@ For information about C# conversions, see the [Conversions](~/_csharpstandard/st The `is` operator also tests an expression result against a pattern. The following example shows how to use a [declaration pattern](patterns.md#declaration-and-type-patterns) to check the run-time type of an expression: -[!code-csharp-interactive[is with declaration pattern](snippets/shared/TypeTestingAndConversionOperators.cs#IsDeclarationPattern)] +:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="IsDeclarationPattern"::: For information about the supported patterns, see [Patterns](patterns.md). -## as operator +## The `as` operator The `as` operator explicitly converts the result of an expression to a given reference or nullable value type. If the conversion isn't possible, the `as` operator returns `null`. Unlike a [cast expression](#cast-expression), the `as` operator never throws an exception. @@ -77,22 +77,22 @@ The expression of the form E as T ``` -where `E` is an expression that returns a value and `T` is the name of a type or a type parameter, produces the same result as +Where `E` is an expression that returns a value and `T` is the name of a type or a type parameter, produces the same result as ```csharp E is T ? (T)(E) : (T)null ``` -except that `E` is only evaluated once. +Except that `E` is only evaluated once. The `as` operator considers only reference, nullable, boxing, and unboxing conversions. You can't use the `as` operator to perform a user-defined conversion. To do that, use a [cast expression](#cast-expression). The following example demonstrates the usage of the `as` operator: -[!code-csharp-interactive[as operator](snippets/shared/TypeTestingAndConversionOperators.cs#AsOperator)] +:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="AsOperator"::: > [!NOTE] -> As the preceding example shows, you need to compare the result of the `as` expression with `null` to check if the conversion is successful. You can use the [is operator](#type-testing-with-pattern-matching) both to test if the conversion succeeds and, if it succeeds, assign its result to a new variable. +> As the preceding example shows, you need to compare the result of the `as` expression with `null` to check if the conversion was successful. You can use the [`is` operator](#type-testing-with-pattern-matching) both to test if the conversion succeeds and, if it succeeds, assign its result to a new variable. ## Cast expression @@ -100,7 +100,7 @@ A cast expression of the form `(T)E` performs an explicit conversion of the resu The following example demonstrates explicit numeric and reference conversions: -[!code-csharp-interactive[cast expression](snippets/shared/TypeTestingAndConversionOperators.cs#Cast)] +:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="Cast"::: For information about supported explicit conversions, see the [Explicit conversions](~/_csharpstandard/standard/conversions.md#103-explicit-conversions) section of the [C# language specification](~/_csharpstandard/standard/README.md). For information about how to define a custom explicit or implicit type conversion, see [User-defined conversion operators](user-defined-conversion-operators.md). @@ -110,11 +110,11 @@ You also use parentheses to [call a method or invoke a delegate](member-access-o Other use of parentheses is to adjust the order in which to evaluate operations in an expression. For more information, see [C# operators](index.md). -## typeof operator +## The `typeof` operator The `typeof` operator obtains the instance for a type. The argument to the `typeof` operator must be the name of a type or a type parameter, as the following example shows: -[!code-csharp-interactive[typeof operator](snippets/shared/TypeTestingAndConversionOperators.cs#TypeOf)] +:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="TypeOf"::: The argument mustn't be a type that requires metadata annotations. Examples include the following types: @@ -125,30 +125,30 @@ These types aren't directly represented in metadata. The types include attribute You can also use the `typeof` operator with unbound generic types. The name of an unbound generic type must contain the appropriate number of commas, which is one less than the number of type parameters. The following example shows the usage of the `typeof` operator with an unbound generic type: -[!code-csharp-interactive[typeof unbound generic](snippets/shared/TypeTestingAndConversionOperators.cs#TypeOfUnboundGeneric)] +:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="TypeOfUnboundGeneric"::: An expression can't be an argument of the `typeof` operator. To get the instance for the run-time type of an expression result, use the method. ### Type testing with the `typeof` operator -Use the `typeof` operator to check if the run-time type of the expression result exactly matches a given type. The following example demonstrates the difference between type checking done with the `typeof` operator and the [is operator](#is-operator): +Use the `typeof` operator to check if the run-time type of the expression result exactly matches a given type. The following example demonstrates the difference between type checking done with the `typeof` operator and the [`is` operator](#the-is-operator): -[!code-csharp[typeof vs is](snippets/shared/TypeTestingAndConversionOperators.cs#TypeCheckWithTypeOf)] +:::code interactive="try-dotnet-method" language="csharp" source="snippets/shared/TypeTestingAndConversionOperators.cs" id="TypeCheckWithTypeOf"::: ## Operator overloadability The `is`, `as`, and `typeof` operators can't be overloaded. -A user-defined type can't overload the `()` operator, but can define custom type conversions that can be performed by a cast expression. For more information, see [User-defined conversion operators](user-defined-conversion-operators.md). +A user-defined type can't overload the `()` operator, but can define custom type conversions performed by a cast expression. For more information, see [User-defined conversion operators](user-defined-conversion-operators.md). ## C# language specification For more information, see the following sections of the [C# language specification](~/_csharpstandard/standard/README.md): -- [The is operator](~/_csharpstandard/standard/expressions.md#121212-the-is-operator) -- [The as operator](~/_csharpstandard/standard/expressions.md#121213-the-as-operator) +- [The `is` operator](~/_csharpstandard/standard/expressions.md#121212-the-is-operator) +- [The `as` operator](~/_csharpstandard/standard/expressions.md#121213-the-as-operator) - [Cast expressions](~/_csharpstandard/standard/expressions.md#1297-cast-expressions) -- [The typeof operator](~/_csharpstandard/standard/expressions.md#12818-the-typeof-operator) +- [The `typeof` operator](~/_csharpstandard/standard/expressions.md#12818-the-typeof-operator) ## 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 e5b5ef50b641d..b8e0f4046708e 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: 11/28/2022 +ms.date: 02/19/2025 f1_keywords: - "explicit_CSharpKeyword" - "implicit_CSharpKeyword" @@ -15,15 +15,15 @@ helpviewer_keywords: --- # User-defined explicit and implicit conversion operators -A user-defined type can define a custom implicit or explicit conversion from or to another type. Implicit conversions don't require special syntax to be invoked and can occur in various situations, for example, in assignments and methods invocations. Predefined C# implicit conversions always succeed and never throw an exception. User-defined implicit conversions should behave in that way as well. If a custom conversion can throw an exception or lose information, define it as an explicit conversion. +A user-defined type can define a custom implicit or explicit conversion from or to another type, provided a standard conversion doesn't exist between the same two types. Implicit conversions don't require special syntax to be invoked and can occur in various situations, for example, in assignments and methods invocations. Predefined C# implicit conversions always succeed and never throw an exception. User-defined implicit conversions should behave in that way as well. If a custom conversion can throw an exception or lose information, define it as an explicit conversion. -User-defined conversions aren't considered by the [is](type-testing-and-cast.md#is-operator) and [as](type-testing-and-cast.md#as-operator) operators. Use a [cast expression](type-testing-and-cast.md#cast-expression) to invoke a user-defined explicit conversion. +The [is](type-testing-and-cast.md#the-is-operator) and [as](type-testing-and-cast.md#the-as-operator) operators don't consider user-defined conversions. Use a [cast expression](type-testing-and-cast.md#cast-expression) to invoke a user-defined explicit conversion. Use the `operator` and `implicit` or `explicit` keywords to define an implicit or explicit conversion, respectively. The type that defines a conversion must be either a source type or a target type of that conversion. A conversion between two user-defined types can be defined in either of the two types. The following example demonstrates how to define an implicit and explicit conversion: -[!code-csharp[implicit an explicit conversions](snippets/shared/UserDefinedConversions.cs)] +:::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. diff --git a/docs/csharp/language-reference/statements/lock.md b/docs/csharp/language-reference/statements/lock.md index 2fd428fc3cea3..6d393e9e743ba 100644 --- a/docs/csharp/language-reference/statements/lock.md +++ b/docs/csharp/language-reference/statements/lock.md @@ -57,7 +57,7 @@ You can't use the [`await` expression](../operators/await.md) in the body of a ` Beginning with .NET 9 and C# 13, lock a dedicated object instance of the type for best performance. In addition, the compiler issues a warning if a known `Lock` object is cast to another type and locked. If using an older version of .NET and C#, lock on a dedicated object instance that isn't used for another purpose. Avoid using the same lock object instance for different shared resources, as it might result in deadlock or lock contention. In particular, avoid using the following instances as lock objects: - `this`, as callers might also lock `this`. -- instances, as they might be obtained by the [typeof](../operators/type-testing-and-cast.md#typeof-operator) operator or reflection. +- instances, as they might be obtained by the [typeof](../operators/type-testing-and-cast.md#the-typeof-operator) operator or reflection. - string instances, including string literals, as they might be [interned](/dotnet/api/system.string.intern#remarks). Hold a lock for as short time as possible to reduce lock contention. diff --git a/docs/csharp/misc/cs0077.md b/docs/csharp/misc/cs0077.md index 750d8b295f7cc..48d6c38428f9f 100644 --- a/docs/csharp/misc/cs0077.md +++ b/docs/csharp/misc/cs0077.md @@ -12,7 +12,7 @@ ms.assetid: 55d3d290-d172-41a3-b326-ebf5a0a7e81f The as operator must be used with a reference type or nullable type ('int' is a non-nullable value type). - The [as](../language-reference/operators/type-testing-and-cast.md#as-operator) operator was passed a [value type](../language-reference/builtin-types/value-types.md). Because `as` can return [null](../language-reference/keywords/null.md), it can only be passed a [reference type](../language-reference/keywords/reference-types.md) or a [nullable value type](../language-reference/builtin-types/nullable-value-types.md). + The [as](../language-reference/operators/type-testing-and-cast.md#the-as-operator) operator was passed a [value type](../language-reference/builtin-types/value-types.md). Because `as` can return [null](../language-reference/keywords/null.md), it can only be passed a [reference type](../language-reference/keywords/reference-types.md) or a [nullable value type](../language-reference/builtin-types/nullable-value-types.md). However, using [pattern matching](../fundamentals/functional/pattern-matching.md) with the [is](../language-reference/operators/is.md) operator, we can directly perform type checking and assignments in one step. diff --git a/docs/csharp/misc/cs0244.md b/docs/csharp/misc/cs0244.md index 874d4c533e5e6..0f754637d1ee0 100644 --- a/docs/csharp/misc/cs0244.md +++ b/docs/csharp/misc/cs0244.md @@ -12,7 +12,7 @@ ms.assetid: f10e4479-ed6e-40dc-9fab-914e404d7f84 Neither 'is' nor 'as' is valid on pointer types - The [is](../language-reference/operators/type-testing-and-cast.md#is-operator) and [as](../language-reference/operators/type-testing-and-cast.md#as-operator) operators are not valid for use on pointer types. For more information, see [Unsafe Code and Pointers](../language-reference/unsafe-code.md). + The [is](../language-reference/operators/type-testing-and-cast.md#the-is-operator) and [as](../language-reference/operators/type-testing-and-cast.md#the-as-operator) operators are not valid for use on pointer types. For more information, see [Unsafe Code and Pointers](../language-reference/unsafe-code.md). The following sample generates CS0244: diff --git a/docs/csharp/misc/cs0837.md b/docs/csharp/misc/cs0837.md index 1bfd6ea5a421b..6c88f16d43435 100644 --- a/docs/csharp/misc/cs0837.md +++ b/docs/csharp/misc/cs0837.md @@ -14,7 +14,7 @@ ms.assetid: cbde45dc-222c-4bfe-8814-856476319d37 The first operand of an 'is' or 'as' operator may not be a lambda expression, anonymous method, or method group. - Lambda expressions, anonymous methods and method groups may not be used on the left side of [is](../language-reference/operators/type-testing-and-cast.md#is-operator) or [as](../language-reference/operators/type-testing-and-cast.md#as-operator). + Lambda expressions, anonymous methods and method groups may not be used on the left side of [is](../language-reference/operators/type-testing-and-cast.md#the-is-operator) or [as](../language-reference/operators/type-testing-and-cast.md#the-as-operator). ## To correct this error diff --git a/docs/csharp/programming-guide/types/casting-and-type-conversions.md b/docs/csharp/programming-guide/types/casting-and-type-conversions.md index 003aa57d50ac0..8b31036f299cd 100644 --- a/docs/csharp/programming-guide/types/casting-and-type-conversions.md +++ b/docs/csharp/programming-guide/types/casting-and-type-conversions.md @@ -1,7 +1,7 @@ --- title: "Casting and type conversions" description: Learn about casting and type conversions, such as implicit, explicit (casts), and user-defined conversions. -ms.date: 03/15/2024 +ms.date: 02/05/2025 helpviewer_keywords: - "type conversion [C#]" - "data type conversion [C#]" @@ -9,12 +9,11 @@ helpviewer_keywords: - "conversions [C#], type" - "casting [C#]" - "converting types [C#]" -ms.assetid: 568df58a-d292-4b55-93ba-601578722878 --- # Casting and type conversions (C# Programming Guide) -Because C# is statically-typed at compile time, after a variable is declared, it can't be declared again or assigned a value of another type unless that type is implicitly convertible to the variable's type. For example, the `string` can't be implicitly converted to `int`. Therefore, after you declare `i` as an `int`, you can't assign the string "Hello" to it, as the following code shows: +Because C# is statically typed at compile time, after a variable is declared, it can't be declared again or assigned a value of another type unless that type is implicitly convertible to the variable's type. For example, the `string` can't be implicitly converted to `int`. Therefore, after you declare `i` as an `int`, you can't assign the string "Hello" to it, as the following code shows: ```csharp int i; @@ -25,64 +24,49 @@ i = "Hello"; However, you might sometimes need to copy a value into a variable or method parameter of another type. For example, you might have an integer variable that you need to pass to a method whose parameter is typed as `double`. Or you might need to assign a class variable to a variable of an interface type. These kinds of operations are called *type conversions*. In C#, you can perform the following kinds of conversions: -- **Implicit conversions**: No special syntax is required because the conversion always succeeds and no data is lost. Examples include conversions from smaller to larger integral types, and conversions from derived classes to base classes. +- **Implicit conversions**: No special syntax is required because the conversion always succeeds and no data is lost. Examples include conversions from smaller to larger integral types, conversions from derived classes to base classes, and span conversions. - **Explicit conversions (casts)**: Explicit conversions require a [cast expression](../../language-reference/operators/type-testing-and-cast.md#cast-expression). Casting is required when information might be lost in the conversion, or when the conversion might not succeed for other reasons. Typical examples include numeric conversion to a type that has less precision or a smaller range, and conversion of a base-class instance to a derived class. - **User-defined conversions**: User-defined conversions use special methods that you can define to enable explicit and implicit conversions between custom types that don't have a base class–derived class relationship. For more information, see [User-defined conversion operators](../../language-reference/operators/user-defined-conversion-operators.md). -- **Conversions with helper classes**: To convert between non-compatible types, such as integers and objects, or hexadecimal strings and byte arrays, you can use the class, the class, and the `Parse` methods of the built-in numeric types, such as . For more information, see [How to convert a byte array to an int](./how-to-convert-a-byte-array-to-an-int.md), [How to convert a string to a number](./how-to-convert-a-string-to-a-number.md), and [How to convert between hexadecimal strings and numeric types](./how-to-convert-between-hexadecimal-strings-and-numeric-types.md). +- **Conversions with helper classes**: To convert between noncompatible types, such as integers and objects, or hexadecimal strings and byte arrays, you can use the class, the class, and the `Parse` methods of the built-in numeric types, such as . For more information, see the following articles: + +- [How to convert a byte array to an int](./how-to-convert-a-byte-array-to-an-int.md) +- [How to convert a string to a number](./how-to-convert-a-string-to-a-number.md) +- [How to convert between hexadecimal strings and numeric types](./how-to-convert-between-hexadecimal-strings-and-numeric-types.md) ## Implicit conversions -For built-in numeric types, an implicit conversion can be made when the value to be stored can fit into the variable without being truncated or rounded off. For integral types, this means the range of the source type is a proper subset of the range for the target type. For example, a variable of type [long](../../language-reference/builtin-types/integral-numeric-types.md) (64-bit integer) can store any value that an [int](../../language-reference/builtin-types/integral-numeric-types.md) (32-bit integer) can store. In the following example, the compiler implicitly converts the value of `num` on the right to a type `long` before assigning it to `bigNum`. +For built-in numeric types, an implicit conversion can be made when the value to be stored can fit into the variable without being truncated or rounded off. For integral types, this restriction means the range of the source type is a proper subset of the range for the target type. For example, a variable of type [long](../../language-reference/builtin-types/integral-numeric-types.md) (64-bit integer) can store any value that an [int](../../language-reference/builtin-types/integral-numeric-types.md) (32-bit integer) can store. In the following example, the compiler implicitly converts the value of `num` on the right to a type `long` before assigning it to `bigNum`. -[!code-csharp[csProgGuideTypes#34](~/samples/snippets/csharp/VS_Snippets_VBCSharp/CsProgGuideTypes/CS/Class1.cs#34)] +:::code language="csharp" source="./snippets/CastingAndConversions/Program.cs" id="ImplicitConversion"::: For a complete list of all implicit numeric conversions, see the [Implicit numeric conversions](../../language-reference/builtin-types/numeric-conversions.md#implicit-numeric-conversions) section of the [Built-in numeric conversions](../../language-reference/builtin-types/numeric-conversions.md) article. For reference types, an implicit conversion always exists from a class to any one of its direct or indirect base classes or interfaces. No special syntax is necessary because a derived class always contains all the members of a base class. -```csharp -Derived d = new Derived(); - -// Always OK. -Base b = d; -``` +:::code language="csharp" source="./snippets/CastingAndConversions/Program.cs" id="ConversionToBase"::: ## Explicit conversions -However, if a conversion can't be made without a risk of losing information, the compiler requires that you perform an explicit conversion, which is called a *cast*. A cast is a way of explicitly informing the compiler that you intend to make the conversion and that you're aware data loss might occur, or the cast may fail at run time. To perform a cast, specify the type that you're casting to in parentheses in front of the value or variable to be converted. The following program casts a [double](../../language-reference/builtin-types/floating-point-numeric-types.md) to an [int](../../language-reference/builtin-types/integral-numeric-types.md). The program won't compile without the cast. +However, if a conversion can't be made without a risk of losing information, the compiler requires that you perform an explicit conversion, which is called a *cast*. A cast is a way of explicitly making the conversion. It indicates you're aware data loss might occur, or the cast might fail at run time. To perform a cast, specify the destination type in parentheses before the expression you want converted. The following program casts a [double](../../language-reference/builtin-types/floating-point-numeric-types.md) to an [int](../../language-reference/builtin-types/integral-numeric-types.md). The program doesn't compile without the cast. -[!code-csharp[csProgGuideTypes#2](~/samples/snippets/csharp/VS_Snippets_VBCSharp/CsProgGuideTypes/CS/Class1.cs#2)] +:::code language="csharp" source="./snippets/CastingAndConversions/Program.cs" id="ExplicitConversion"::: For a complete list of supported explicit numeric conversions, see the [Explicit numeric conversions](../../language-reference/builtin-types/numeric-conversions.md#explicit-numeric-conversions) section of the [Built-in numeric conversions](../../language-reference/builtin-types/numeric-conversions.md) article. For reference types, an explicit cast is required if you need to convert from a base type to a derived type: -```csharp -// Create a new derived type. -Giraffe g = new Giraffe(); - -// Implicit conversion to base type is safe. -Animal a = g; - -// Explicit conversion is required to cast back -// to derived type. Note: This will compile but will -// throw an exception at run time if the right-side -// object is not in fact a Giraffe. -Giraffe g2 = (Giraffe)a; -``` - A cast operation between reference types doesn't change the run-time type of the underlying object; it only changes the type of the value that is being used as a reference to that object. For more information, see [Polymorphism](../../fundamentals/object-oriented/polymorphism.md). ## Type conversion exceptions at run time In some reference type conversions, the compiler can't determine whether a cast is valid. It's possible for a cast operation that compiles correctly to fail at run time. As shown in the following example, a type cast that fails at run time causes an to be thrown. -[!code-csharp[csProgGuideTypes#41](~/samples/snippets/csharp/VS_Snippets_VBCSharp/CsProgGuideTypes/CS/Class1.cs#41)] +:::code language="csharp" source="./snippets/CastingAndConversions/Program.cs" id="UnsafeCast"::: -The `Test` method has an `Animal` parameter, thus explicitly casting the argument `a` to a `Reptile` makes a dangerous assumption. It's safer to not make assumptions, but rather check the type. C# provides the [is](../../language-reference/operators/type-testing-and-cast.md#is-operator) operator to enable you to test for compatibility before actually performing a cast. For more information, see [How to safely cast using pattern matching and the as and is operators](../../fundamentals/tutorials/safely-cast-using-pattern-matching-is-and-as-operators.md). +Explicitly casting the argument `a` to a `Reptile` makes a dangerous assumption. It's safer to not make assumptions, but rather check the type. C# provides the [`is`](../../language-reference/operators/type-testing-and-cast.md#the-is-operator) operator to enable you to test for compatibility before actually performing a cast. For more information, see [How to safely cast using pattern matching and the as and is operators](../../fundamentals/tutorials/safely-cast-using-pattern-matching-is-and-as-operators.md). ## C# language specification diff --git a/docs/csharp/programming-guide/types/snippets/CastingAndConversions/CastingAndConversions.csproj b/docs/csharp/programming-guide/types/snippets/CastingAndConversions/CastingAndConversions.csproj new file mode 100644 index 0000000000000..fd4bd08da2987 --- /dev/null +++ b/docs/csharp/programming-guide/types/snippets/CastingAndConversions/CastingAndConversions.csproj @@ -0,0 +1,10 @@ + + + + Exe + net9.0 + enable + enable + + + diff --git a/docs/csharp/programming-guide/types/snippets/CastingAndConversions/Program.cs b/docs/csharp/programming-guide/types/snippets/CastingAndConversions/Program.cs new file mode 100644 index 0000000000000..8c65dc5fec95f --- /dev/null +++ b/docs/csharp/programming-guide/types/snippets/CastingAndConversions/Program.cs @@ -0,0 +1,54 @@ +// +// Implicit conversion. A long can +// hold any value an int can hold, and more! +int num = 2147483647; +long bigNum = num; +// + +// +Derived d = new Derived(); + +// Always OK. +Base b = d; +// + +// +double x = 1234.7; +int a; +// Cast double to int. +a = (int)x; +Console.WriteLine(a); +// Output: 1234 +// + +// +// Create a new derived type. +Giraffe g = new Giraffe(); + +// Implicit conversion to base type is safe. +Animal a = g; + +// Explicit conversion is required to cast back +// to derived type. Note: This will compile but will +// throw an exception at run time if the right-side +// object is not in fact a Giraffe. +Giraffe g2 = (Giraffe)a; +// + +// +Animal a = new Mammal(); +Reptile r = (Reptile)a; // InvalidCastException at run time +// + + +public class B {} + +public class C : B {} + + +class Animal { } + +class Reptile : Animal { } +class Mammal : Animal { } + +public class Giraffe : Animal {} diff --git a/docs/csharp/specification/toc.yml b/docs/csharp/specification/toc.yml index 888f1ec5ec335..56dbe3ff9267f 100644 --- a/docs/csharp/specification/toc.yml +++ b/docs/csharp/specification/toc.yml @@ -115,6 +115,10 @@ items: href: ../../../_csharplang/proposals/csharp-10.0/improved-definite-assignment.md - name: Ref readonly parameters href: ../../../_csharplang/proposals/csharp-12.0/ref-readonly-parameters.md + - name: Conversions + items: + - name: First class span types + href: ../../../_csharplang/proposals/first-class-span-types.md - name: Patterns items: - name: Recursive pattern matching @@ -155,6 +159,8 @@ items: href: ../../../_csharplang/proposals/csharp-13.0/method-group-natural-type-improvements.md - name: Optional Lambda expression parameters href: ../../../_csharplang/proposals/csharp-12.0/lambda-method-group-defaults.md + - name: Simple lambda parameters with modifiers + href: ../../../_csharplang/proposals/simple-lambda-parameters-with-modifiers.md - name: Checked user-defined operators href: ../../../_csharplang/proposals/csharp-11.0/checked-user-defined-operators.md - name: Unsigned right-shift operator @@ -165,6 +171,8 @@ items: href: ../../../_csharplang/proposals/csharp-10.0/caller-argument-expression.md - name: Extended nameof scope href: ../../../_csharplang/proposals/csharp-11.0/extended-nameof-scope.md + - name: Unbound generic types in nameof + href: ../../../_csharplang/proposals/unbound-generic-types-in-nameof.md - name: Overload resolution priority href: ../../../_csharplang/proposals/csharp-13.0/overload-resolution-priority.md - name: Statements diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index 1a9b3afe25780..4e0ed7fd66832 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -148,6 +148,8 @@ items: items: - name: C# 14 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 diff --git a/docs/csharp/whats-new/csharp-11.md b/docs/csharp/whats-new/csharp-11.md index 807efe5e84542..f56d00e40cf24 100644 --- a/docs/csharp/whats-new/csharp-11.md +++ b/docs/csharp/whats-new/csharp-11.md @@ -45,7 +45,7 @@ public class TypeAttribute : Attribute } ``` -And to apply the attribute, you use the [`typeof`](../language-reference/operators/type-testing-and-cast.md#typeof-operator) operator: +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))] @@ -77,7 +77,7 @@ public class GenericType } ``` -The type arguments must satisfy the same restrictions as the [`typeof`](../language-reference/operators/type-testing-and-cast.md#typeof-operator) operator. Types that require metadata annotations aren't allowed. For example, the following types aren't allowed as the type parameter: +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) diff --git a/docs/csharp/whats-new/csharp-13.md b/docs/csharp/whats-new/csharp-13.md index 8c0dedc8d60ed..a05526babd353 100644 --- a/docs/csharp/whats-new/csharp-13.md +++ b/docs/csharp/whats-new/csharp-13.md @@ -25,8 +25,6 @@ C# 13 is supported on **.NET 9**. For more information, see [C# language version You can download the latest .NET 9 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 9 SDK. -New features are added to the "What's new in C#" page when they're available in public preview releases. The [working set](https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md#working-set) section of the [roslyn feature status page](https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md) tracks when upcoming features are merged into the main branch. - You can find any breaking changes introduced in C# 13 in our article on [breaking changes](~/_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%209.md). [!INCLUDE [released-version-feedback](./includes/released-feedback.md)] diff --git a/docs/csharp/whats-new/csharp-14.md b/docs/csharp/whats-new/csharp-14.md new file mode 100644 index 0000000000000..12c3e930cffe8 --- /dev/null +++ b/docs/csharp/whats-new/csharp-14.md @@ -0,0 +1,100 @@ +--- +title: What's new in C# 14 +description: Get an overview of the new features in C# 14. C# 14 ships with .NET 10. +ms.date: 02/19/2025 +ms.topic: whats-new +--- +# What's new in C# 14 + +C# 14 includes the following new features. You can try these features using the latest [Visual Studio 2022](https://visualstudio.microsoft.com/vs/preview/) version or the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet): + +- [`nameof` supports unbound generic types](#unbound-generic-types-and-nameof) +- [More implicit conversions for `Span` and `ReadOnlySpan`](#implicit-span-conversions) +- [Modifiers on simple lambda parameters](#simple-lambda-parameters-with-modifiers) +- [`field` backed properties](#the-field-keyword) + +C# 14 is supported on **.NET 10**. For more information, see [C# language versioning](../language-reference/configure-language-version.md). + +You can download the latest .NET 10 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 10 SDK. + +New features are added to the "What's new in C#" page when they're available in public preview releases. The [working set](https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md#working-set) section of the [roslyn feature status page](https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md) tracks when upcoming features are merged into the main branch. + +You can find any breaking changes introduced in C# 14 in our article on [breaking changes](~/_roslyn/docs/compilers/CSharp/Compiler%20Breaking%20Changes%20-%20DotNet%2010.md). + +[!INCLUDE [released-version-feedback](./includes/released-feedback.md)] + +## The `field` keyword + +The token `field` enables you to write a property accessor body without declaring an explicit backing field. The token `field` is replaced with a compiler synthesized backing field. + +For example, previously, if you wanted to ensure that a `string` property couldn't be set to `null`, you had to declare a backing field and implement both accessors: + +```csharp +private string _msg; +public string Message +{ + get => _msg; + set + { + if (value is null) throw new NullArgumentException(nameof(value)); + _msg = value; + } +} +``` + +You can now simplify your code to: + +```csharp +public string Message +{ + get; + set + { + field = (value is not null) ? value : throw new NullArgumentException(nameof(value)); + } +} +``` + +You can declare a body for one or both accessors for a field backed property. + +There's a potential breaking change or confusion reading code in types that also include a symbol named `field`. You can use `@field` or `this.field` to disambiguate between the `field` keyword and the identifier, or you can rename the current `field` symbol to provide more distinction. + +[!INCLUDE[field-preview](../includes/field-preview.md)] + +If you try this feature and have feedback, comment on the [feature issue](https://github.com/dotnet/csharplang/issues/140) in the `csharplang` repository. + +The [`field`](../language-reference/keywords/field.md) contextual keyword is in C# 13 as a preview feature. You can try it if you're using .NET 9 and C# 13 to provide [feedback](https://github.com/dotnet/csharplang/issues/140). + +## Implicit span conversions + +C# 14 introduces first-class support for and in the language. This support involves new implicit conversions allowing more natural programming with these types. + +`Span` and `ReadOnlySpan` are used in many key ways in C# and the runtime. Their introduction improves performance without risking safety. C# 14 recognizes the relationship and supports some conversions between `ReadOnlySpan`, `Span`, and `T[]`. The span types can be extension method receivers, compose with other conversions, and help with generic type inference scenarios. + +You can find the list of implicit span conversions in the article on [built-in types](../language-reference/builtin-types/built-in-types.md) in the language reference section. You can learn more details by reading the feature specification for [First class span types](~/_csharplang/proposals/first-class-span-types.md). + +## Unbound generic types and nameof + +Beginning with C# 14, the argument to `nameof` can be an unbound generic type. For example, `nameof(List<>)` evaluates to `List`. In earlier versions of C#, only closed generic types, such as `List`, could be used to return the `List` name. + +## Simple lambda parameters with modifiers + +Beginning with C# 14, you can add parameter modifiers, such as `scoped`, `ref`, `in`, `out`, or `ref readonly` to lambda expression parameters without specifying the parameter type: + +```csharp +delegate bool TryParse(string text, out T result); +// ... +TryParse parse1 = (text, out result) => Int32.TryParse(text, out result); +``` + +Previously, adding any modifiers was allowed only when the parameter declarations included the types for the parameters. The preceding declaration would require typs on all parameters: + +```csharp +TryParse parse2 = (string text, out int result) => Int32.TryParse(text, out result); +``` + +The `params` modifier still requires an explicitly typed parameter list. + +You can read more about these changes in the article on [lambda expressions](../language-reference/operators/lambda-expressions.md#input-parameters-of-a-lambda-expression) in the C# language reference. + + diff --git a/docs/framework/data/adonet/sql/linq/basic-data-types.md b/docs/framework/data/adonet/sql/linq/basic-data-types.md index f74488000f2a4..65a67339b9963 100644 --- a/docs/framework/data/adonet/sql/linq/basic-data-types.md +++ b/docs/framework/data/adonet/sql/linq/basic-data-types.md @@ -18,7 +18,7 @@ Because LINQ to SQL queries translate to Transact-SQL before they are executed o - Equal and Inequality Operator: Equality and inequality operators are supported for numeric, , , and types. For more about Visual Basic operators `=` and `<>`, see [Comparison Operators](../../../../../visual-basic/language-reference/operators/comparison-operators.md). For more information about C# comparison operators `==` and `!=`, see [Equality operators](../../../../../csharp/language-reference/operators/equality-operators.md). -- Is operator: The `IS` operator has a supported translation when inheritance mapping is being used. It can be used instead of directly testing the discriminator column to determine whether an object is of a specific entity type, and is translated to a check on the discriminator column. For more information about the Visual Basic and C# Is operators, see [Is Operator](../../../../../visual-basic/language-reference/operators/is-operator.md) and [is](../../../../../csharp/language-reference/operators/type-testing-and-cast.md#is-operator). +- Is operator: The `IS` operator has a supported translation when inheritance mapping is being used. It can be used instead of directly testing the discriminator column to determine whether an object is of a specific entity type, and is translated to a check on the discriminator column. For more information about the Visual Basic and C# Is operators, see [Is Operator](../../../../../visual-basic/language-reference/operators/is-operator.md) and [is](../../../../../csharp/language-reference/operators/type-testing-and-cast.md#the-is-operator). ## See also diff --git a/docs/fundamentals/code-analysis/quality-rules/ca2263.md b/docs/fundamentals/code-analysis/quality-rules/ca2263.md index 572da2d56c8f1..26031debfd7e5 100644 --- a/docs/fundamentals/code-analysis/quality-rules/ca2263.md +++ b/docs/fundamentals/code-analysis/quality-rules/ca2263.md @@ -30,7 +30,7 @@ A method overload that accepts a arg ## Rule description -Generic overloads are preferable to overloads that accept an argument of type when the type is known at compile time (using the [typeof operator](../../../csharp/language-reference/operators/type-testing-and-cast.md#typeof-operator) in C# or the [GetType operator](../../../visual-basic/language-reference/operators/gettype-operator.md) in Visual Basic). Generic overloads promote cleaner and more type-safe code with improved compile-time checks. +Generic overloads are preferable to overloads that accept an argument of type when the type is known at compile time (using the [typeof operator](../../../csharp/language-reference/operators/type-testing-and-cast.md#the-typeof-operator) in C# or the [GetType operator](../../../visual-basic/language-reference/operators/gettype-operator.md) in Visual Basic). Generic overloads promote cleaner and more type-safe code with improved compile-time checks. ## How to fix violations diff --git a/docs/fundamentals/code-analysis/style-rules/ide0082.md b/docs/fundamentals/code-analysis/style-rules/ide0082.md index e77a77b32d6eb..6f30073788f84 100644 --- a/docs/fundamentals/code-analysis/style-rules/ide0082.md +++ b/docs/fundamentals/code-analysis/style-rules/ide0082.md @@ -24,7 +24,7 @@ dev_langs: ## Overview -This style rule recommends use of the [nameof operator](../../../csharp/language-reference/operators/nameof.md) over the [typeof operator](../../../csharp/language-reference/operators/type-testing-and-cast.md#typeof-operator) followed by member access. It only fires when the name will be identical in both cases. +This style rule recommends use of the [nameof operator](../../../csharp/language-reference/operators/nameof.md) over the [typeof operator](../../../csharp/language-reference/operators/type-testing-and-cast.md#the-typeof-operator) followed by member access. It only fires when the name will be identical in both cases. ## Options @@ -81,6 +81,6 @@ For more information, see [How to suppress code analysis warnings](../suppress-w ## See also - [nameof operator](../../../csharp/language-reference/operators/nameof.md) -- [typeof operator](../../../csharp/language-reference/operators/type-testing-and-cast.md#typeof-operator) +- [typeof operator](../../../csharp/language-reference/operators/type-testing-and-cast.md#the-typeof-operator) - [Code style language rules](language-rules.md) - [Code style rules reference](index.md) diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/CsProgGuideTypes/CS/Class1.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/CsProgGuideTypes/CS/Class1.cs index 44d7f0ed595d8..736a882650a24 100644 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/CsProgGuideTypes/CS/Class1.cs +++ b/samples/snippets/csharp/VS_Snippets_VBCSharp/CsProgGuideTypes/CS/Class1.cs @@ -19,20 +19,6 @@ static void TestCasting() } // - // - class Test - { - static void Main() - { - double x = 1234.7; - int a; - // Cast double to int. - a = (int)x; - System.Console.WriteLine(a); - } - } - // Output: 1234 - // } //------------------------------------------------------------------------- @@ -452,12 +438,6 @@ class ValueTypeConversion { static void Main() { - // - // Implicit conversion. A long can - // hold any value an int can hold, and more! - int num = 2147483647; - long bigNum = num; - // } } @@ -593,37 +573,6 @@ void UseAsWithNullable(System.ValueType val) } // - // - class Animal - { - public void Eat() => System.Console.WriteLine("Eating."); - - public override string ToString() => "I am an animal."; - } - - class Reptile : Animal { } - class Mammal : Animal { } - - class UnSafeCast - { - static void Main() - { - Test(new Mammal()); - - // Keep the console window open in debug mode. - System.Console.WriteLine("Press any key to exit."); - System.Console.ReadKey(); - } - - static void Test(Animal a) - { - // System.InvalidCastException at run time - // Unable to cast object of type 'Mammal' to type 'Reptile' - Reptile r = (Reptile)a; - } - } - // - // class ValueTypeDemo {