Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Notitie
Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.
Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. Deze verschillen worden vastgelegd in de relevante LDM-notities (Language Design Meeting).
Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.
Kampioenprobleem https://github.com/dotnet/csharplang/issues/8374
Samenvatting
Updates voor de betere conversieregels om consistenter te zijn met paramsen om de huidige dubbelzinnigheidsscenario's beter af te handelen. Zo kan ReadOnlySpan<string> versus ReadOnlySpan<object> momenteel ambiguïteit veroorzaken tijdens overbelastingsresolutie voor [""].
Gedetailleerd ontwerp
Hier volgen de beste conversies van expressieregels. Deze vervangen de regels in https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution.
Deze regels zijn:
Gezien een impliciete conversie
C₁die wordt geconverteerd van een expressieEnaar een typeT₁en een impliciete conversieC₂die converteert van een expressieEnaar een typeT₂, isC₁een betere conversie danC₂als een van de volgende bewaringen geldt:
Eis een verzamelingsexpressieenC₁is een betere verzamelingsconversie van expressies danC₂Eis geen verzameluitdrukking en een van de volgende situaties geldt:
Ekomt exact overeen metT₁enEkomt niet exact overeen metT₂Ekomt exact overeen met zowelT₁alsT₂, of met geen van beide, enT₁is een beter conversiedoel danT₂Eis een methodegroep, ...
We voegen als volgt een nieuwe definitie toe voor betere verzamelingsconversie van expressies:
Gegeven:
-
Eis een verzamelingsexpressie met elementexpressies[EL₁, EL₂, ..., ELₙ] -
T₁enT₂zijn verzamelingstypen -
E₁is het elementtype vanT₁ -
E₂is het elementtype vanT₂ -
CE₁ᵢzijn de reeks conversies vanELᵢtotE₁ -
CE₂ᵢzijn de reeks conversies vanELᵢtotE₂
Als er een identiteitsconversie is van E₁ naar E₂, zijn de elementconversies net zo goed als elkaar. Anders zijn de elementconversies naar E₁ beter dan de elementconversies naar E₂ als:
- Voor elke
ELᵢisCE₁ᵢminstens zo goed alsCE₂ᵢ, en - Er is ten minste één i waar
CE₁ᵢbeter is danCE₂ᵢAnders is geen van beide set elementconversies beter dan de andere, en ze zijn ook niet zo goed als elkaar.
Conversievergelijkingen worden gemaakt met een betere conversie van expressies alsELᵢgeen verspreid element is. AlsELᵢeen verspreid element is, gebruiken we respectievelijk een betere conversie van het elementtype van de verspreidingsverzameling naarE₁ofE₂.
C₁ is een betere verzamelingsconversie van expressies dan C₂ als:
- Zowel
T₁alsT₂zijn geen span types, enT₁is impliciet converteerbaar naarT₂, enT₂is niet impliciet converteerbaar naarT₁, of -
E₁heeft geen identiteitsconversie naarE₂en de elementconversies naarE₁zijn beter dan de elementconversies naarE₂, of -
E₁heeft een identiteitsconversie naarE₂en een van de volgende geldt:-
T₁isSystem.ReadOnlySpan<E₁>enT₂isSystem.Span<E₂>, of... -
T₁is gelijk aanSystem.ReadOnlySpan<E₁>ofSystem.Span<E₁>, enT₂is een array_or_array_interface met het elementtypeE₂
-
Anders is geen van beide verzamelingstypen beter en is het resultaat dubbelzinnig.
Notitie
Deze regels betekenen dat methoden die overbelastingen blootstellen die verschillende elementtypen gebruiken en zonder conversie tussen de verzamelingstypen dubbelzinnig zijn voor lege verzamelingsexpressies. Als voorbeeld:
public void M(ReadOnlySpan<int> ros) { ... }
public void M(Span<int?> span) { ... }
M([]); // Ambiguous
Scenario 's:
In het Engels moeten de verzamelingstypen zelf hetzelfde zijn of ondubbelzinnig beter zijn (d.w.w.v. List<T> en List<T> hetzelfde zijn, List<T> is ondubbelzinnig beter dan IEnumerable<T>, en List<T> en HashSet<T> niet kunnen worden vergeleken), en de elementconversies voor het betere verzamelingstype moeten ook hetzelfde of beter zijn (we kunnen niet kiezen tussen ReadOnlySpan<object> en Span<string> voor [""], de gebruiker moet die beslissing nemen). Meer voorbeelden hiervan zijn:
T₁ |
T₂ |
E |
C₁ conversies |
C₂ conversies |
CE₁ᵢ versus CE₂ᵢ |
Resultaat |
|---|---|---|---|---|---|---|
List<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ is beter |
List<int> wordt gekozen |
List<int> |
List<byte> |
[(int)1, (byte)2] |
[Identity, Implicit Numeric] |
Niet van toepassing |
T₂ is niet van toepassing |
List<int> wordt gekozen |
List<int> |
List<byte> |
[1, (byte)2] |
[Identity, Implicit Numeric] |
[Implicit Constant, Identity] |
Geen van beide is beter | Dubbelzinnig |
List<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ is beter |
List<byte> wordt gekozen |
List<int?> |
List<long> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
Geen van beide is beter | Dubbelzinnig |
List<int?> |
List<ulong> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ is beter |
List<int?> wordt gekozen |
List<short> |
List<long> |
[1, 2, 3] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ is beter |
List<short> wordt gekozen |
IEnumerable<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ is beter |
IEnumerable<int> wordt gekozen |
IEnumerable<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ is beter |
List<byte> wordt gekozen |
int[] |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ is beter |
int[] wordt gekozen |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", "", ""] |
[Identity, Identity, Identity] |
[Implicit Reference, Implicit Reference, Implicit Reference] |
CE₁ᵢ is beter |
ReadOnlySpan<string> wordt gekozen |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", new object()] |
Niet van toepassing | [Implicit Reference, Identity] |
T₁ is niet van toepassing |
ReadOnlySpan<object> wordt gekozen |
ReadOnlySpan<object> |
Span<string> |
["", ""] |
[Implicit Reference] |
[Identity] |
CE₂ᵢ is beter |
Span<string> wordt gekozen |
ReadOnlySpan<object> |
Span<string> |
[new object()] |
[Identity] |
Niet van toepassing |
T₁ is niet van toepassing |
ReadOnlySpan<object> wordt gekozen |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{1}"] |
[Interpolated String Handler] |
[Identity] |
CE₁ᵢ is beter |
ReadOnlySpan<InterpolatedStringHandler> wordt gekozen |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{"blah"}"] |
[Interpolated String Handler] |
[Identity] - Maar constante |
CE₂ᵢ is beter |
ReadOnlySpan<string> wordt gekozen |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}"] |
[Identity] |
[Interpolated String] |
CE₂ᵢ is beter |
ReadOnlySpan<string> wordt gekozen |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}", (FormattableString)null] |
Niet van toepassing | [Interpolated String, Identity] |
T₁ is niet van toepassing |
ReadOnlySpan<FormattableString> wordt gekozen |
HashSet<short> |
Span<long> |
[1, 2] |
[Implicit Constant, Implicit Constant] |
[Implicit Numeric, Implicit Numeric] |
CE₁ᵢ is beter |
HashSet<short> wordt gekozen |
HashSet<long> |
Span<short> |
[1, 2] |
[Implicit Numeric, Implicit Numeric] |
[Implicit Constant, Implicit Constant] |
CE₂ᵢ is beter |
Span<short> wordt gekozen |
Open vragen
Hoe ver moeten we prioriteit geven aan ReadOnlySpan/Span boven andere typen?
Zoals vandaag is opgegeven, zijn de volgende overbelastingen dubbelzinnig:
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> {}
Hoe ver willen we hierheen? De List<T> variant lijkt redelijk, en subtypen van List<T> bestaan in overvloed. Maar de HashSet versie heeft heel andere semantiek, hoe zeker zijn we dat het eigenlijk 'erger' is dan ReadOnlySpan in deze API?
C# feature specifications