Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Dieser Artikel ist eine Feature-Spezifikation. Die Spezifikation dient als Designdokument für das Feature. Es enthält vorgeschlagene Spezifikationsänderungen sowie Informationen, die während des Entwurfs und der Entwicklung des Features erforderlich sind. Diese Artikel werden veröffentlicht, bis die vorgeschlagenen Spezifikationsänderungen abgeschlossen und in die aktuelle ECMA-Spezifikation aufgenommen werden.
Es kann einige Abweichungen zwischen der Feature-Spezifikation und der abgeschlossenen Implementierung geben. Diese Unterschiede werden in den entsprechenden Hinweisen zum Language Design Meeting (LDM) erfasst.
Weitere Informationen zum Prozess für die Aufnahme von Funktions-Speclets in den C#-Sprachstandard finden Sie im Artikel zu den Spezifikationen.
Champion-Problem: https://github.com/dotnet/csharplang/issues/8374
Zusammenfassung
Aktualisierungen der besseren Konvertierungsregeln, um konsistenter mit params zu sein und aktuelle Mehrdeutigkeits-Szenarien besser zu behandeln. Zum Beispiel kann ReadOnlySpan<string> vs. ReadOnlySpan<object> derzeit Mehrdeutigkeiten während der Überladungsauflösung für [""] verursachen.
Detailliertes Design
Die Folgenden sind die besseren Konvertierungen aus Ausdrucksregeln. Diese ersetzen die Regeln in https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution.
Diese Regeln sind:
Gegeben eine implizite Konvertierung
C₁, die von einem AusdruckEzu einem TypT₁konvertiert, und eine implizite KonvertierungC₂, die von einem AusdruckEzu einem TypT₂konvertiert, istC₁eine bessere Konvertierung alsC₂, wenn eine der folgenden Bedingungen erfüllt ist:
Eist ein Sammlungs-Ausdruck, undC₁ist eine bessere Sammlungs-Konvertierung aus Ausdruck alsC₂Eist kein Sammlungs-Ausdruck und eine der folgenden Bedingungen gilt:
Estimmt genau mitT₁überein undEstimmt nicht genau mitT₂übereinEstimmt genau mit beiden oder keinem vonT₁undT₂überein, undT₁ist ein besseres Konvertierungsziel alsT₂Eist eine Methodengruppe, ...
Wir fügen eine neue Definition für bessere Sammlungs-Konvertierung aus Ausdruck hinzu, wie folgt:
Gegeben:
-
Eist ein Sammlungs-Ausdruck mit Elementausdrücken[EL₁, EL₂, ..., ELₙ] -
T₁undT₂sind Sammlungstypen -
E₁ist der Elementtyp vonT₁ -
E₂ist der Elementtyp vonT₂ -
CE₁ᵢsind die Serie von Konvertierungen vonELᵢzuE₁ -
CE₂ᵢsind die Serie von Konvertierungen vonELᵢzuE₂
Wenn es eine Identitätskonvertierung von E₁ zu E₂ gibt, sind die Elementkonvertierungen genauso gut wie die jeweils andere. Andernfalls sind die Elementkonvertierungen zu E₁besser als die Elementkonvertierungen zu E₂, wenn:
- Für jedes
ELᵢistCE₁ᵢmindestens so gut wieCE₂ᵢ, und - Es gibt mindestens ein i, bei dem
CE₁ᵢbesser ist alsCE₂ᵢ, andernfalls ist keine Gruppe von Elementkonvertierungen besser als die andere, und sie sind einander auch nicht überlegen.
Konvertierungsvergleiche werden mit besseren Konvertierungen aus Ausdruck durchgeführt, wennELᵢkein Spread-Element ist. WennELᵢein Spread-Element ist, verwenden wir die bessere Konvertierung vom Elementtyp der Spread-Sammlung jeweils zuE₁oderE₂.
C₁ ist eine bessere Sammlungs-Konvertierung aus Ausdruck als C₂, wenn:
- Beide
T₁undT₂keine Span-Typen sind, undT₁implizit konvertierbar zuT₂ist, undT₂nicht implizit konvertierbar zuT₁ist, oder -
E₁keine Identitätskonvertierung zuE₂hat, und die Elementkonvertierungen zuE₁besser als die Elementkonvertierungen zuE₂sind, oder -
E₁eine Identitätskonvertierung zuE₂hat, und eine der folgenden Bedingungen erfüllt ist:-
T₁istSystem.ReadOnlySpan<E₁>, undT₂istSystem.Span<E₂>, oder -
T₁istSystem.ReadOnlySpan<E₁>oderSystem.Span<E₁>, undT₂ist ein array_or_array_interface mit ElementtypE₂
-
Andernfalls ist kein Sammlungstyp besser, und das Ergebnis ist mehrdeutig.
Hinweis
Diese Regeln bedeuten, dass Methoden, die Überladungen bereitstellen, die unterschiedliche Elementtypen verwenden und keine Konvertierung zwischen den Sammlungstypen zulassen, für leere Sammlungs-Ausdrücke mehrdeutig sind. Beispiel:
public void M(ReadOnlySpan<int> ros) { ... }
public void M(Span<int?> span) { ... }
M([]); // Ambiguous
Szenarien:
In verständlicher Sprache müssen die Sammlungstypen selbst entweder identisch oder eindeutig besser sein (d.h. List<T> und List<T> sind identisch, List<T> ist eindeutig besser als IEnumerable<T>, und List<T> und HashSet<T> können nicht verglichen werden), und die Elementkonvertierungen für den besseren Sammlungstyp müssen ebenfalls identisch oder besser sein (d.h., wir können nicht zwischen ReadOnlySpan<object> und Span<string> für [""]entscheiden, da der Benutzer diese Entscheidung treffen muss). Weitere Beispiele:
T₁ |
T₂ |
E |
C₁ Konvertierungen |
C₂ Konvertierungen |
CE₁ᵢ vs. CE₂ᵢ |
Ergebnis |
|---|---|---|---|---|---|---|
List<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ ist besser |
List<int> wird ausgewählt |
List<int> |
List<byte> |
[(int)1, (byte)2] |
[Identity, Implicit Numeric] |
Nicht zutreffend |
T₂ ist nicht zutreffend |
List<int> wird ausgewählt |
List<int> |
List<byte> |
[1, (byte)2] |
[Identity, Implicit Numeric] |
[Implicit Constant, Identity] |
Keine Version ist besser | Nicht eindeutig |
List<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ ist besser |
List<byte> wird ausgewählt |
List<int?> |
List<long> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
Keine Version ist besser | Nicht eindeutig |
List<int?> |
List<ulong> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ ist besser |
List<int?> wird ausgewählt |
List<short> |
List<long> |
[1, 2, 3] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ ist besser |
List<short> wird ausgewählt |
IEnumerable<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ ist besser |
IEnumerable<int> wird ausgewählt |
IEnumerable<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ ist besser |
List<byte> wird ausgewählt |
int[] |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ ist besser |
int[] wird ausgewählt |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", "", ""] |
[Identity, Identity, Identity] |
[Implicit Reference, Implicit Reference, Implicit Reference] |
CE₁ᵢ ist besser |
ReadOnlySpan<string> wird ausgewählt |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", new object()] |
Nicht zutreffend | [Implicit Reference, Identity] |
T₁ ist nicht zutreffend |
ReadOnlySpan<object> wird ausgewählt |
ReadOnlySpan<object> |
Span<string> |
["", ""] |
[Implicit Reference] |
[Identity] |
CE₂ᵢ ist besser |
Span<string> wird ausgewählt |
ReadOnlySpan<object> |
Span<string> |
[new object()] |
[Identity] |
Nicht zutreffend |
T₁ ist nicht zutreffend |
ReadOnlySpan<object> wird ausgewählt |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{1}"] |
[Interpolated String Handler] |
[Identity] |
CE₁ᵢ ist besser |
ReadOnlySpan<InterpolatedStringHandler> wird ausgewählt |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{"blah"}"] |
[Interpolated String Handler] |
[Identity] - Aber konstant |
CE₂ᵢ ist besser |
ReadOnlySpan<string> wird ausgewählt |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}"] |
[Identity] |
[Interpolated String] |
CE₂ᵢ ist besser |
ReadOnlySpan<string> wird ausgewählt |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}", (FormattableString)null] |
Nicht zutreffend | [Interpolated String, Identity] |
T₁ ist nicht zutreffend |
ReadOnlySpan<FormattableString> wird ausgewählt |
HashSet<short> |
Span<long> |
[1, 2] |
[Implicit Constant, Implicit Constant] |
[Implicit Numeric, Implicit Numeric] |
CE₁ᵢ ist besser |
HashSet<short> wird ausgewählt |
HashSet<long> |
Span<short> |
[1, 2] |
[Implicit Numeric, Implicit Numeric] |
[Implicit Constant, Implicit Constant] |
CE₂ᵢ ist besser |
Span<short> wird ausgewählt |
Offene Fragen
In welchem Ausmaß sollten wir ReadOnlySpan/Span über andere typen priorisieren?
Wie derzeit festgelegt, wären die folgenden Überladungen mehrdeutig:
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> {}
Wie weit möchten wir hier gehen? Die List<T>-Variante scheint vernünftig, und Untertypen von List<T> existieren reichlich. Aber die HashSet-Version hat sehr unterschiedliche Semantik. Wie sicher sind wir, dass sie tatsächlich „schlechter“ ist als ReadOnlySpan in dieser API?
C# feature specifications