diff --git a/docs/core/compatibility/9.0.md b/docs/core/compatibility/9.0.md index 4c102c09a0bf7..9761602e51bbe 100644 --- a/docs/core/compatibility/9.0.md +++ b/docs/core/compatibility/9.0.md @@ -41,6 +41,7 @@ If you're migrating an app to .NET 9, the breaking changes listed here might aff | [API obsoletions with custom diagnostic IDs](core-libraries/9.0/obsolete-apis-with-custom-diagnostics.md) | Source incompatible | (Multiple) | | [BigInteger maximum length](core-libraries/9.0/biginteger-limit.md) | Behavioral change | Preview 6 | | [BinaryReader.GetString() returns "\uFFFD" on malformed sequences](core-libraries/9.0/binaryreader.md) | Behavioral change | Preview 7 | +| [C# overload resolution prefers `params` span-type overloads](core-libraries/9.0/params-overloads.md) | Source incompatible | | | [Creating type of array of System.Void not allowed](core-libraries/9.0/type-instance.md) | Behavioral change | Preview 1 | | [Default `Equals()` and `GetHashCode()` throw for types marked with `InlineArrayAttribute`](core-libraries/9.0/inlinearrayattribute.md) | Behavioral change | Preview 6 | | [EnumConverter validates registered types to be enum](core-libraries/9.0/enumconverter.md) | Behavioral change | Preview 7 | diff --git a/docs/core/compatibility/core-libraries/9.0/params-overloads.md b/docs/core/compatibility/core-libraries/9.0/params-overloads.md new file mode 100644 index 0000000000000..11ef67d729d73 --- /dev/null +++ b/docs/core/compatibility/core-libraries/9.0/params-overloads.md @@ -0,0 +1,122 @@ +--- +title: "Breaking change: C# overload resolution prefers `params` span-type overloads" +description: Learn about the breaking change in .NET 9 where C# overload resolution prefers `params` span-type overloads, which can't be used in `Expression` lambdas. +ms.date: 12/16/2024 +--- + +# C# overload resolution prefers `params` span-type overloads + +C# 13 added support for `params` parameters declared with collection types other than arrays. In particular, `params ReadOnlySpan` and `params Span` are supported, and overload resolution prefers a `params` span type over a `params` array type when both are applicable. + +.NET 9 [added `params` span overloads for various methods](../../../whats-new/dotnet-9/libraries.md#params-readonlyspant-overloads) in the core .NET libraries. Those methods had pre-existing overloads that took `params` arrays. When you recompile code with existing calls to those methods where arguments are passed in expanded form, the compiler will now bind to the `params` span overload. + +The new binding leads to a potential breaking change for existing calls to those overloads within lambda expressions, which don't support `ref struct` instances. In those cases, the C# 13 compiler reports an error when binding to the `params` span overload. + +For example, consider `string.Join()`: + +```csharp +using System; +using System.Linq.Expressions; + +Expression> join = + (x, y) => string.Join("", x, y); +``` + +When compiled with .NET 8, the call binds to , without errors. + +When compiled with C# 13 and .NET 9, the call binds to , and because the call is within an [expression tree](xref:System.Linq.Expressions.Expression), the following errors are reported: + +> error CS8640: Expression tree cannot contain value of ref struct or restricted type 'ReadOnlySpan'. +> error CS9226: An expression tree may not contain an expanded form of non-array params + +## Version introduced + +.NET 9 + +## Previous behavior + +Prior to C# 13, `params` parameters were limited to array types only. Calls to those methods in expanded form resulted in implicit array instances only, which are supported in lambda expressions. + +## New behavior + +With C# 13 and .NET 9, for methods with overloads that take `params` array types and `params` span types, overload resolution prefers the `params` span overload. Such a call creates an implicit span instance at the call site. For calls within lambda expressions, the implicit `ref struct` span instance is reported as a compiler error. + +## Type of breaking change + +This change can affect [source compatibility](../../categories.md#source-compatibility). + +## Reason for change + +The new method overloads were added for performance reasons. `params` span support allows the compiler to avoid an allocation for the `params` argument at the call site. + +## Recommended action + +If your code is affected, the recommended workaround is to call the method with an explicit array so the call binds to the `params` array overload. + +For the previous example, use `new string[] { ... }`: + +```csharp +Expression> join = + (x, y) => string.Join("", new string[] { x, y }); +``` + +## Affected APIs + +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- + +## See also + +- [What's new: `params ReadOnlySpan` overloads](../../../whats-new/dotnet-9/libraries.md#params-readonlyspant-overloads) diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index 8fb2fd4eea23b..69ec5b8149d1e 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -36,6 +36,8 @@ items: href: core-libraries/9.0/obsolete-apis-with-custom-diagnostics.md - name: BigInteger maximum length href: core-libraries/9.0/biginteger-limit.md + - name: C# overload resolution prefers `params` span-type overloads + href: core-libraries/9.0/params-overloads.md - name: Creating type of array of System.Void not allowed href: core-libraries/9.0/type-instance.md - name: EnumConverter validates registered types to be enum @@ -1304,6 +1306,8 @@ items: href: core-libraries/9.0/biginteger-limit.md - name: BinaryReader.GetString() returns "/uFFFD" on malformed sequences href: core-libraries/9.0/binaryreader.md + - name: C# overload resolution prefers `params` span-type overloads + href: core-libraries/9.0/params-overloads.md - name: Creating type of array of System.Void not allowed href: core-libraries/9.0/type-instance.md - name: EnumConverter validates registered types to be enum