|
| 1 | +--- |
| 2 | +title: "Breaking change: C# 14 overload resolution with span parameters" |
| 3 | +description: Learn about the .NET 10 breaking change in core .NET libraries where overloads with span parameters are applicable in more scenarios. |
| 4 | +ms.date: 01/30/2025 |
| 5 | +--- |
| 6 | +# C# 14 overload resolution with span parameters |
| 7 | + |
| 8 | +C# 14 introduces new [built-in span conversions and type inference rules](https://github.com/dotnet/csharplang/issues/7905) making overloads with span parameters applicable in more scenarios. |
| 9 | + |
| 10 | +## Previous behavior |
| 11 | + |
| 12 | +In C# 13 and earlier, an extension method taking a `ReadOnlySpan<T>` or `Span<T>` receiver is not applicable to a value of type `T[]`. Therefore, only non-span extension methods like the ones from the `System.Linq.Enumerable` class are usually bound inside Expression lambdas. |
| 13 | + |
| 14 | +## New behavior |
| 15 | + |
| 16 | +In C# 14 and later, methods with `ReadOnlySpan<T>` or `Span<T>` parameters can participate in type inference or be used as extension methods in more scenarios. This makes span-based methods like the ones from the `System.MemoryExtensions` class bind in more scenarios, including inside Expression lambdas where they will cause runtime exceptions when compiled with interpretation. |
| 17 | + |
| 18 | +## Version introduced |
| 19 | + |
| 20 | +.NET 10 Preview 1 |
| 21 | + |
| 22 | +## Type of breaking change |
| 23 | + |
| 24 | +This change is a [behavioral change](../../categories.md#behavioral-change). |
| 25 | + |
| 26 | +## Reason for change |
| 27 | + |
| 28 | +The C# language feature allows simplified API design and usage (e.g., one ReadOnlySpan extension method can apply to both spans and arrays). |
| 29 | + |
| 30 | +## Recommended action |
| 31 | + |
| 32 | +If you need to continue using Expression interpretation, you should make sure the non-span overloads are bound, e.g., by casting arguments to the exact types the method signature takes or calling the extension methods as explicit static invocations: |
| 33 | + |
| 34 | +```cs |
| 35 | +using System; |
| 36 | +using System.Collections.Generic; |
| 37 | +using System.Linq; |
| 38 | +using System.Linq.Expressions; |
| 39 | + |
| 40 | +M((array, num) => array.Contains(num)); // fails, binds to MemoryExtensions.Contains |
| 41 | +M((array, num) => ((IEnumerable<int>)array).Contains(num)); // ok, binds to Enumerable.Contains |
| 42 | +M((array, num) => array.AsEnumerable().Contains(num)); // ok, binds to Enumerable.Contains |
| 43 | +M((array, num) => Enumerable.Contains(array, num)); // ok, binds to Enumerable.Contains |
| 44 | +
|
| 45 | +void M(Expression<Func<int[], int, bool>> e) => e.Compile(preferInterpretation: true); |
| 46 | +``` |
| 47 | + |
| 48 | +## Affected APIs |
| 49 | + |
| 50 | +- <xref:System.Linq.Expressions.Expression`1.Compile*?displayProperty=fullName> |
0 commit comments