Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for nameof for open generic types, first class span implicit conversions, and implicit lambda parameters with modifiers #44641

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions .github/workflows/snippets5000.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down
6 changes: 3 additions & 3 deletions .openpublishing.redirection.csharp.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
},
{
Expand Down
12 changes: 10 additions & 2 deletions docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@
"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"
],
"src": "_csharplang/proposals",
"dest": "csharp/language-reference/proposals",
Expand Down Expand Up @@ -504,7 +506,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",
Expand Down Expand Up @@ -680,6 +682,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",
Expand Down Expand Up @@ -801,6 +806,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<T>` and `ReadOnlySpan<T>` that enable library authors to have fewer overloads and developers to write code that resolves to faster Span based APIs",
"_csharplang/proposals/simle-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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <xref:System.InvalidCastException>. 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 <xref:System.InvalidCastException>. 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:

Expand Down
2 changes: 1 addition & 1 deletion docs/csharp/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 12 additions & 2 deletions docs/csharp/language-reference/builtin-types/built-in-types.md
Original file line number Diff line number Diff line change
@@ -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/04/2025
helpviewer_keywords:
- "types [C#], built-in"
- "built-in C# types"
Expand Down Expand Up @@ -36,7 +36,7 @@ The following table lists the C# built-in [reference](../keywords/reference-type
|[`string`](reference-types.md#the-string-type)|<xref:System.String?displayProperty=nameWithType>|
|[`dynamic`](reference-types.md#the-dynamic-type)|<xref:System.Object?displayProperty=nameWithType>|

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;
Expand All @@ -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 <xref:System.Span`1?displayProperty=fullName> and <xref:System.ReadOnlySpan`1?displayProperty=fullName> 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<T>` and `ReadOnlySpan<T>`. 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<E>`
- From any single-dimensional array with element type `E` to `System.ReadOnlySpan<U>`, when `E` has covariance conversion or an identity conversion to `U`
- From `System.Span<E>` to `System.ReadOnlySpan<U>`, when `E` has a covariance conversion or an identity conversion to `U`
- From `System.ReadOnlySpan<E>` to `System.ReadOnlySpan<U>`, when `E` has a covariance conversion or an identity conversion to `U`
- From `string` to `System.ReadOnlySpan<char>`

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)
Expand Down
4 changes: 2 additions & 2 deletions docs/csharp/language-reference/builtin-types/collections.md
Original file line number Diff line number Diff line change
@@ -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 <xref:System.Array?displayProperty=nameWithType>, <xref:System.Span%601?displayProperty=nameWithType>, and <xref:System.Memory%601?displayProperty=nameWithType> are recognized in the C# language. In addition, interfaces like <xref:System.Collections.Generic.IEnumerable%601?displayProperty=nameWithType> 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 <xref:System.Array?displayProperty=nameWithType>, <xref:System.Span%601?displayProperty=nameWithType>, and <xref:System.Memory%601?displayProperty=nameWithType> are recognized [in the C# language](./built-in-types.md). In addition, interfaces like <xref:System.Collections.Generic.IEnumerable%601?displayProperty=nameWithType> 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:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,17 @@ The following example shows how to determine whether a <xref:System.Type?display

[!code-csharp-interactive[whether Type is nullable](snippets/shared/NullableValueTypes.cs#IsTypeNullable)]

As the example shows, you use the [typeof](../operators/type-testing-and-cast.md#typeof-operator) operator to create a <xref:System.Type?displayProperty=nameWithType> instance.
As the example shows, you use the [typeof](../operators/type-testing-and-cast.md#the-typeof-operator) operator to create a <xref:System.Type?displayProperty=nameWithType> instance.

If you want to determine whether an instance is of a nullable value type, don't use the <xref:System.Object.GetType%2A?displayProperty=nameWithType> method to get a <xref:System.Type> instance to be tested with the preceding code. When you call the <xref:System.Object.GetType%2A?displayProperty=nameWithType> method on an instance of a nullable value type, the instance is [boxed](#boxing-and-unboxing) to <xref:System.Object>. As boxing of a non-null instance of a nullable value type is equivalent to boxing of a value of the underlying type, <xref:System.Object.GetType%2A> returns a <xref:System.Type> 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 <xref:System.Nullable.GetUnderlyingType%2A?displayProperty=nameWithType> 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 <xref:System.Nullable.GetUnderlyingType%2A?displayProperty=nameWithType> 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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <xref:System.Type?displayProperty=nameWithType> 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 <xref:System.Type?displayProperty=nameWithType> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
Loading
Loading