代码检查:C# 14 在带有 span 参数的重载解析中的重大变化
C# 14 引入了新的 内置 span 转换和类型推断规则。 这使得带有 span 参数的重载在更多场景中适用,但也带来了一些 重大变化。
JetBrains Rider 会识别可能受到这些重大变化影响的位置,并建议对其进行审查。 并非所有发生更改的行为都会在编译或运行时导致错误,因此无需修复所有建议项。 建议在审查所有发生项并修复可能在编译或运行时导致错误的项后,禁用此检查。
之前的行为
在 C# 14 之前,带有 ReadOnlySpan<T> 或 Span<T> 参数的扩展方法无法直接应用于类型为 T[] 的数组。 因此,在处理数组时,编译器仅在方法解析期间选择非 span 扩展方法(例如,在 System.Linq.Enumerable 类中定义的方法)。
新的行为
从 C# 14 开始,接受 ReadOnlySpan<T> 或 Span<T> 参数的方法具备了类型推断的扩展能力,并可作为更广泛上下文中的扩展方法使用。 因此,在诸如 System.MemoryExtensions 等库中定义的基于 span 的方法现在可适用于其他场景,在这些场景中,它们可能会意外地引发运行时异常。
示例
对于协变数组,在选择使用 Span<T> 的重载时于运行时 ArrayTypeMismatchException:
string[] strings = new[] { "a" };
M(strings);
void M(object[] possibleCovariantArray)
{
// ok with C# 13 because it uses overload with IEnumerable<T>,
// but in C# 14, ArrayTypeMismatchException is thrown at runtime
// when converting a covariant array to Span<object>
Util.DoSomething(possibleCovariantArray);
}
static class Util
{
public static void DoSomething<T>(IEnumerable<T> e) =>
Console.Write("IEnumerable<T>");
public static void DoSomething<T>(Span<T> s) =>
Console.Write("Span<T>");
}
由于重载解析规则发生更改,导致编译错误:
string[] strings = new[] { "a" };
// C# 13 uses overload with IEnumerable<T>, which has a return type,
// but C# 14 uses overload with Span<T>, which has no return type
_ = strings.Reverse();
static class Util
{
public static IEnumerable<T> Reverse<T>(this IEnumerable<T> e) =>
throw new NotImplementedException();
public static void Reverse<T>(this Span<T> s) =>
throw new NotImplementedException();
}
在使用解释编译的表达式 lambda 中发生运行时异常:
using System.Linq.Expressions;
// ok with C# 13, but causes a runtime exception in C# 14
// because it uses overload with ReadOnlySpan<T>
M((array, num) => array.Contains(num));
void M(Expression<Func<int[], int, bool>> e) =>
e.Compile(preferInterpretation: true);
在官方 Microsoft 文档中了解更多信息:
最后修改日期: 2025年 12月 5日