Edit

Share via


C# 14 overload resolution with span parameters

C# 14, which ships with .NET 10, introduces new built-in span conversions and type inference rules. Those changes make overloads with span parameters applicable in more scenarios.

Previous behavior

In C# 13 and earlier, an extension method taking a ReadOnlySpan<T> or Span<T> receiver was not applicable to a value of type T[]. Therefore, only non-span extension methods like the ones from the System.Linq.Enumerable class were usually bound inside Expression lambdas.

New behavior

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.

Version introduced

.NET 10

Type of breaking change

This change is a behavioral change.

Reason for change

The C# language feature allows simplified API design and usage (for example, one ReadOnlySpan<T> extension method can apply to both spans and arrays).

If you need to continue using Expression interpretation, make sure the non-span overloads are bound, for example, by casting arguments to the exact types the method signature takes or calling the extension methods as explicit static invocations:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

M((array, num) => array.Contains(num)); // fails, binds to MemoryExtensions.Contains
M((array, num) => ((IEnumerable<int>)array).Contains(num)); // ok, binds to Enumerable.Contains
M((array, num) => array.AsEnumerable().Contains(num)); // ok, binds to Enumerable.Contains
M((array, num) => Enumerable.Contains(array, num)); // ok, binds to Enumerable.Contains

void M(Expression<Func<int[], int, bool>> e) => e.Compile(preferInterpretation: true);

Affected APIs