Поделиться через


Разрешение перегрузок C# предпочитает перегрузки диапазонного типа params.

C# 13 добавил поддержку параметров params, объявленных с типами коллекций, отличными от массивов. В частности, поддерживаются params ReadOnlySpan<T> и params Span<T>, а разрешение перегрузки предпочитает тип диапазона params по сравнению с типом массива params, если они применимы.

В .NET 9 добавлены перегрузки методов для работы с диапазонами params для различных методов в основных библиотеках .NET. Эти методы имели уже существующие перегрузки, которые принимали массивы params. При повторной компиляции кода с существующими вызовами этих методов, в которых аргументы передаются в развернутой форме, компилятор теперь привязывается к перегрузке диапазона params.

Новая привязка приводит к потенциальному критическому изменению существующих вызовов к этим перегрузкам в Expression лямбда-выражениях, которые не поддерживают 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.

Новое поведение

При использовании C# 13 и .NET 9 для методов с перегрузками, которые принимают массивные типы params и типы диапазонов params, разрешение перегрузки предпочитает перегрузку для типа диапазона params. Такой вызов создает неявный экземпляр диапазона в месте вызова. Для вызовов в лямбда-выражениях Expression неявный экземпляр диапазона ref struct сообщается как ошибка компилятора.

Тип критического изменения

Это изменение может повлиять на совместимость исходного кода.

Причина изменения

Новые перегрузки методов были добавлены по соображениям производительности. Поддержка диапазонов params позволяет компилятору избежать выделения для аргумента params в точке вызова.

Если ваш код затронут, рекомендуемое решение заключается в вызове метода с явным массивом, чтобы вызов привязывается к перегрузке массива params.

В предыдущем примере используйте new string[] { ... }:

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

Затронутые API

См. также