Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Poznámka
Tento článek je specifikace funkce. Specifikace slouží jako návrhový dokument pro funkci. Zahrnuje navrhované změny specifikace spolu s informacemi potřebnými při návrhu a vývoji funkce. Tyto články se publikují, dokud nebudou navrhované změny specifikace finalizovány a začleněny do aktuální specifikace ECMA.
Mezi specifikací funkce a dokončenou implementací může docházet k nějakým nesrovnalostem. Tyto rozdíly jsou zachyceny v poznámkách ze schůzky návrhu jazyka (LDM) .
Další informace o procesu přijetí specifikací funkcí do jazyka C# najdete v článku o specifikacích .
Problém šampiona: https://github.com/dotnet/csharplang/issues/8374
Shrnutí
Aktualizace lepších pravidel převodu tak, aby byly konzistentnější s paramsa lépe zvládly aktuální scénáře nejednoznačnosti. Například ReadOnlySpan<string> vs. ReadOnlySpan<object> může v současné době způsobit nejednoznačnost při rozlišení přetížení pro [""].
Podrobný návrh
Následuje účinnější převod podle pravidel výrazů. Nahradí pravidla v https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution.
Tato pravidla jsou:
Vzhledem k implicitnímu převodu
C₁, který převádí z výrazuEna typT₁, a implicitnímu převoduC₂, který převádí z výrazuEna typT₂, jeC₁lepší převod nežC₂, pokud platí jedna z následujících možností:
Eje výraz pro kolekci aC₁je lepší konverze kolekce z výrazu nežC₂Enení výrazem kolekce a platí jeden z následujících:
Epřesně odpovídáT₁aEpřesně neodpovídáT₂Epřesně odpovídá buď oběma, nebo ani jednomu zT₁aT₂, aT₁je lepším cílovým objektem konverze nežT₂Eje skupina metod, ...
Přidáme novou definici pro lepší převod kolekce z výrazunásledujícím způsobem:
Daný:
-
Eje výraz kolekce s elementárními výrazy[EL₁, EL₂, ..., ELₙ] -
T₁aT₂jsou typy kolekcí. -
E₁je typ prvkuT₁ -
E₂je typ prvkuT₂ -
CE₁ᵢjsou série převodů zELᵢnaE₁ -
CE₂ᵢjsou série převodů zELᵢnaE₂
Pokud existuje převod identity z E₁ na E₂, pak jsou převody prvků stejně dobré jako navzájem. Jinak jsou převody prvků na E₁lepší než převody prvků na E₂, pokud:
- Pro každý
ELᵢjeCE₁ᵢalespoň tak dobrý jakoCE₂ᵢa - Existuje alespoň jedno i, kde je
CE₁ᵢlepší nežCE₂ᵢ. Jinak ani jedna sada prvkových převodů není lepší než druhá, a nejsou ani stejně dobré.
Porovnání převodů se provádí pomocí lepšího převodu z výrazu, pokudELᵢnení rozprostřený prvek. Pokud jeELᵢrozšiřující prvek, použijeme lepší konverzi z typu prvku rozšiřující kolekce naE₁neboE₂, v daném pořadí.
C₁ je lepší převod kolekce z výrazu než C₂, pokud:
-
T₁iT₂nejsou typy rozsahůaT₁se implicitně konvertibilní naT₂aT₂se implicitně nepřevést naT₁nebo -
E₁nemá identitní převod naE₂a převody prvků naE₁jsou lepší než převody prvků naE₂nebo -
E₁má identitní převod naE₂a platí jedna z následujících podmínek:-
T₁jeSystem.ReadOnlySpan<E₁>aT₂jeSystem.Span<E₂>nebo -
T₁jeSystem.ReadOnlySpan<E₁>neboSystem.Span<E₁>, aT₂je rozhraní pole_nebo_pole s prvkem typuE₂
-
Jinak není žádný typ kolekce lepší a výsledek je nejednoznačný.
Poznámka
Tato pravidla znamenají, že metody, které poskytují přetížení přijímající různé typy prvků a postrádající konverzi mezi typy kolekcí, jsou nejednoznačné pro výrazy prázdných kolekcí. Příklad:
public void M(ReadOnlySpan<int> ros) { ... }
public void M(Span<int?> span) { ... }
M([]); // Ambiguous
Scénáře:
V prosté angličtině musí být samotné typy kolekcí buď stejné, nebo jednoznačně lepší (tj. List<T> a List<T> jsou stejné, List<T> je jednoznačně lepší než IEnumerable<T>a List<T> a HashSet<T> nelze porovnat) a prvky pro lepší typ kolekce musí být také stejné nebo lepší (tj. nemůžeme rozhodnout mezi ReadOnlySpan<object> a Span<string> pro [""], uživatel musí učinit toto rozhodnutí). Tady jsou další příklady:
T₁ |
T₂ |
E |
C₁ převody |
C₂ převody |
CE₁ᵢ vs. CE₂ᵢ |
Výsledek |
|---|---|---|---|---|---|---|
List<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ je lepší |
List<int> je vybráno |
List<int> |
List<byte> |
[(int)1, (byte)2] |
[Identity, Implicit Numeric] |
Nepoužitelné |
T₂ se nedá použít |
List<int> je vybráno |
List<int> |
List<byte> |
[1, (byte)2] |
[Identity, Implicit Numeric] |
[Implicit Constant, Identity] |
Ani jeden z nich není lepší | Mnohoznačný |
List<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ je lepší |
List<byte> je vybráno |
List<int?> |
List<long> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
Ani jeden z nich není lepší | Mnohoznačný |
List<int?> |
List<ulong> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ je lepší |
List<int?> je vybráno |
List<short> |
List<long> |
[1, 2, 3] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ je lepší |
List<short> je vybráno |
IEnumerable<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ je lepší |
IEnumerable<int> je vybráno |
IEnumerable<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ je lepší |
List<byte> je vybráno |
int[] |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ je lepší |
int[] je vybráno |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", "", ""] |
[Identity, Identity, Identity] |
[Implicit Reference, Implicit Reference, Implicit Reference] |
CE₁ᵢ je lepší |
ReadOnlySpan<string> je vybráno |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", new object()] |
Nepoužitelné | [Implicit Reference, Identity] |
T₁ se nedá použít |
ReadOnlySpan<object> je vybráno |
ReadOnlySpan<object> |
Span<string> |
["", ""] |
[Implicit Reference] |
[Identity] |
CE₂ᵢ je lepší |
Span<string> je vybráno |
ReadOnlySpan<object> |
Span<string> |
[new object()] |
[Identity] |
Nepoužitelné |
T₁ se nedá použít |
ReadOnlySpan<object> je vybráno |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{1}"] |
[Interpolated String Handler] |
[Identity] |
CE₁ᵢ je lepší |
ReadOnlySpan<InterpolatedStringHandler> je vybráno |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{"blah"}"] |
[Interpolated String Handler] |
[Identity] – ale konstanta |
CE₂ᵢ je lepší |
ReadOnlySpan<string> je vybráno |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}"] |
[Identity] |
[Interpolated String] |
CE₂ᵢ je lepší |
ReadOnlySpan<string> je vybráno |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}", (FormattableString)null] |
Nepoužitelné | [Interpolated String, Identity] |
T₁ se nedá použít |
ReadOnlySpan<FormattableString> je vybráno |
HashSet<short> |
Span<long> |
[1, 2] |
[Implicit Constant, Implicit Constant] |
[Implicit Numeric, Implicit Numeric] |
CE₁ᵢ je lepší |
HashSet<short> je vybráno |
HashSet<long> |
Span<short> |
[1, 2] |
[Implicit Numeric, Implicit Numeric] |
[Implicit Constant, Implicit Constant] |
CE₂ᵢ je lepší |
Span<short> je vybráno |
Otevřené otázky
Jak daleko bychom měli upřednostnit ReadOnlySpan/Span oproti jiným typům?
Jak je uvedeno dnes, následující přetížení by bylo nejednoznačné:
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> {}
Jak daleko chceme jít sem? Varianta List<T> se zdá rozumná a podtypů List<T> existuje spousta. Ale verze HashSet má velmi odlišnou sémantiku, jak jsme si jistí, že je skutečně horší než ReadOnlySpan v tomto rozhraní API?
C# feature specifications