Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Заметка
Эта статья является спецификацией компонентов. Спецификация служит проектным документом для функции. Она включает предлагаемые изменения спецификации, а также информацию, необходимую во время проектирования и разработки функции. Эти статьи публикуются до тех пор, пока предложенные изменения спецификации не будут завершены и включены в текущую спецификацию ECMA.
Может возникнуть некоторое несоответствие между спецификацией компонентов и завершенной реализацией. Эти различия фиксируются в соответствующих заметках собраний по разработке языка (LDM) .
Дополнительные сведения о процессе внедрения спецификаций функций в стандарт языка C# см. в статье о спецификациях .
Проблема чемпиона: https://github.com/dotnet/csharplang/issues/8374
Сводка
Обновляются правила преобразования, которые должны быть более согласованными с paramsи более эффективно обрабатывать текущие сценарии неоднозначности. Например, ReadOnlySpan<string> и ReadOnlySpan<object> в настоящее время могут вызвать неоднозначность во время разрешения перегрузки для [""].
Подробный дизайн
Ниже приведено лучшее преобразование из правил выражений. Эти правила заменяют правила в https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution.
Ниже приведены следующие правила:
Учитывая неявное преобразование
C₁, которое преобразуется из выраженияEв типT₁, и неявное преобразованиеC₂, которое преобразуется из выраженияEв типT₂,C₁— это лучшее преобразование, чемC₂, если выполняется одно из следующих условий:
. — это выражение коллекции , а — это лучшее преобразование коллекции из выражения, чем Eне является выражением коллекции , и выполняется одно из следующих условий:
Eточно совпадает сT₁, аEне полностью соответствуетT₂Eточно соответствует либо обоимT₁иT₂, либо ни тому, ни другому, аT₁— это лучшее целевое преобразование по сравнению сT₂.E— это группа методов, ...
Мы добавляем новое определение для для более эффективного преобразования коллекции из выраженияследующим образом:
Данный:
-
E— это выражение коллекции с выражениями элементов[EL₁, EL₂, ..., ELₙ] -
T₁иT₂являются типами коллекций -
E₁— это тип элементаT₁ -
E₂— это тип элементаT₂ -
CE₁ᵢ— это ряд преобразований изELᵢвE₁ -
CE₂ᵢ— это ряд преобразований изELᵢвE₂
Если существует тождественное преобразование из E₁ в E₂, то преобразования элементов так же хороши друг, как и друг. В противном случае преобразования элементов в E₁лучше, чем преобразования элементов в E₂, если:
- Для каждого
ELᵢCE₁ᵢне менее хорош, чемCE₂ᵢ, и - Существует по крайней мере один i, где
CE₁ᵢлучше, чемCE₂ᵢ. В противном случае ни один набор преобразований элементов не лучше другого, и они также не такие хорошие, как друг друга.
Сравнения преобразований выполняются с помощью более эффективного преобразования из выражения, еслиELᵢне является элементом распространения. ЕслиELᵢявляется элементом распространения, мы используем лучшее преобразование из типа элемента коллекции распространения вE₁илиE₂соответственно.
C₁ — это лучшее преобразование коллекции из выражения, чем C₂, если:
- Оба
T₁иT₂не типы диапазонов, иT₁неявно преобразуется вT₂, иT₂неявно преобразуется вT₁или -
E₁не имеет преобразования идентичности вE₂, а преобразования элементов вE₁лучше, чем преобразования элементов вE₂, или же... -
E₁имеет тождественное преобразование вE₂и выполняется одно из следующих условий.-
T₁этоSystem.ReadOnlySpan<E₁>, иT₂этоSystem.Span<E₂>, или -
T₁System.ReadOnlySpan<E₁>илиSystem.Span<E₁>,T₂— это array_or_array_interface с типом элементаE₂
-
В противном случае ни один тип коллекции не лучше, и результат неоднозначный.
Заметка
Эти правила означают, что методы, предоставляющие перегрузки, работающие с разными типами элементов без преобразования между типами коллекций, являются неоднозначными для пустых выражений для коллекций. В качестве примера:
public void M(ReadOnlySpan<int> ros) { ... }
public void M(Span<int?> span) { ... }
M([]); // Ambiguous
Сценарии:
На обычном английском языке сами типы коллекций должны быть одинаковыми. или однозначно лучше (т. е. List<T> и List<T> совпадают, List<T> однозначно лучше, чем IEnumerable<T>, а List<T> и HashSet<T> нельзя сравнить), а преобразования элементов для лучшего типа коллекции также должны быть одинаковыми или более лучшими (т. е. мы не можем решить между ReadOnlySpan<object> и Span<string> для [""], пользователь должен принять это решение). Ниже приведены дополнительные примеры:
T₁ |
T₂ |
E |
C₁ Преобразования |
C₂ Преобразования |
CE₁ᵢ и CE₂ᵢ |
Результат |
|---|---|---|---|---|---|---|
List<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ лучше |
List<int> выбран |
List<int> |
List<byte> |
[(int)1, (byte)2] |
[Identity, Implicit Numeric] |
Неприменимо |
T₂ неприменимо |
List<int> выбран |
List<int> |
List<byte> |
[1, (byte)2] |
[Identity, Implicit Numeric] |
[Implicit Constant, Identity] |
Ни один не лучше | Двусмысленный |
List<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ лучше |
List<byte> выбран |
List<int?> |
List<long> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
Ни один не лучше | Двусмысленный |
List<int?> |
List<ulong> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ лучше |
List<int?> выбран |
List<short> |
List<long> |
[1, 2, 3] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ лучше |
List<short> выбран |
IEnumerable<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ лучше |
IEnumerable<int> выбран |
IEnumerable<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ лучше |
List<byte> выбран |
int[] |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ лучше |
int[] выбран |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", "", ""] |
[Identity, Identity, Identity] |
[Implicit Reference, Implicit Reference, Implicit Reference] |
CE₁ᵢ лучше |
ReadOnlySpan<string> выбран |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", new object()] |
Неприменимо | [Implicit Reference, Identity] |
T₁ неприменимо |
ReadOnlySpan<object> выбран |
ReadOnlySpan<object> |
Span<string> |
["", ""] |
[Implicit Reference] |
[Identity] |
CE₂ᵢ лучше |
Span<string> выбран |
ReadOnlySpan<object> |
Span<string> |
[new object()] |
[Identity] |
Неприменимо |
T₁ неприменимо |
ReadOnlySpan<object> выбран |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{1}"] |
[Interpolated String Handler] |
[Identity] |
CE₁ᵢ лучше |
ReadOnlySpan<InterpolatedStringHandler> выбран |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{"blah"}"] |
[Interpolated String Handler] |
[Identity] - Но константа |
CE₂ᵢ лучше |
ReadOnlySpan<string> выбран |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}"] |
[Identity] |
[Interpolated String] |
CE₂ᵢ лучше |
ReadOnlySpan<string> выбран |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}", (FormattableString)null] |
Неприменимо | [Interpolated String, Identity] |
T₁ неприменимо |
ReadOnlySpan<FormattableString> выбран |
HashSet<short> |
Span<long> |
[1, 2] |
[Implicit Constant, Implicit Constant] |
[Implicit Numeric, Implicit Numeric] |
CE₁ᵢ лучше |
HashSet<short> выбран |
HashSet<long> |
Span<short> |
[1, 2] |
[Implicit Numeric, Implicit Numeric] |
[Implicit Constant, Implicit Constant] |
CE₂ᵢ лучше |
Span<short> выбран |
Открытые вопросы
В какой степени мы должны расставлять приоритеты ReadOnlySpan/Span над другими типами?
Как указано сегодня, следующие перегрузки будут неоднозначными:
C.M1(["Hello world"]); // Ambiguous, no tiebreak between ROS and List
C.M2(["Hello world"]); // Ambiguous, no tiebreak between Span and List
C.M3(["Hello world"]); // Ambiguous, no tiebreak between ROS and MyList.
C.M4(["Hello", "Hello"]); // Ambiguous, no tiebreak between ROS and HashSet. Created collections have different contents
class C
{
public static void M1(ReadOnlySpan<string> ros) {}
public static void M1(List<string> list) {}
public static void M2(Span<string> ros) {}
public static void M2(List<string> list) {}
public static void M3(ReadOnlySpan<string> ros) {}
public static void M3(MyList<string> list) {}
public static void M4(ReadOnlySpan<string> ros) {}
public static void M4(HashSet<string> hashset) {}
}
class MyList<T> : List<T> {}
Насколько далеко мы хотим пойти сюда? Вариант List<T> кажется разумным, и подтипов List<T> существует много. Но версия HashSet имеет очень другую семантику, насколько мы уверены, что это на самом деле "хуже", чем ReadOnlySpan в этом API?
C# feature specifications