C# 重载解析首选 params 范围类型重载

C# 13 添加了对 params 使用数组以外的集合类型声明的参数的支持。 具体而言, params ReadOnlySpan<T> 并且 params Span<T> 受支持,重载解析在两者都适用时更喜欢 params 范围类型而不是 params 数组类型。

.NET 9 为核心 .NET 库 params中的各种方法添加了 范围重载。 这些方法具有采用 params 数组的预先存在的重载。 当你使用对那些以扩展形式传递参数的方法的现有调用重新编译代码时,编译器现在将绑定到 params 范围重载。

新绑定导致对 Expression lambda 表达式内的重载的现有调用发生潜在的重大更改,这些表达式不支持 ref struct 实例。 在这些情况下,C# 13 编译器在绑定到 params 范围重载时报告错误。

例如,请考虑 string.Join()

using System;
using System.Linq.Expressions;

Expression<Func<string, string, string>> join =
    (x, y) => string.Join("", x, y);

使用 .NET 8 编译时,调用将 Join(String, String[])绑定到,而不会出错。

使用 C# 13 和 .NET 9 编译时,调用将绑定到 Join(String, ReadOnlySpan<String>),并且由于调用位于 表达式树中,因此将报告以下错误:

错误 CS8640:表达式树不能包含 ref 结构或受限类型“ReadOnlySpan”的值。 错误 CS9226:表达式树可能不包含非数组参数的扩展形式

已引入的版本

.NET 9

以前的行为

在 C# 13 之前, params 参数仅限于数组类型。 以扩展形式调用这些方法只会产生隐式数组实例,这些实例在 Expression lambda 表达式中得到支持。

新行为

使用 C# 13 和 .NET 9,对于具有采用 params 数组类型和 params 范围类型的重载的方法,重载解析首选 params 范围重载。 此类调用在调用站点创建隐式跨度实例。 对于 lambda 表达式中的 Expression 调用,隐式 ref struct span 实例被报告为编译器错误。

破坏性变更的类型

此更改可能会影响 源兼容性

更改原因

为了提升性能,添加了新方法重载。 params 范围支持使编译器能够在调用站点上避免为 params 参数进行分配。

如果代码受到影响,建议的解决方法是使用显式数组调用方法,以便调用绑定到 params 数组重载。

对于前面的示例,请使用 new string[] { ... }

Expression<Func<string, string, string>> join =
    (x, y) => string.Join("", new string[] { x, y });

受影响的 API

另请参阅