Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Jegyzet
Ez a cikk egy funkcióspecifikáció. A specifikáció a funkció tervezési dokumentumaként szolgál. Tartalmazza a specifikáció javasolt módosításait, valamint a funkció tervezése és fejlesztése során szükséges információkat. Ezeket a cikkeket mindaddig közzéteszik, amíg a javasolt specifikációmódosításokat nem véglegesítik, és be nem építik a jelenlegi ECMA-specifikációba.
A szolgáltatás specifikációja és a befejezett implementáció között eltérések lehetnek. Ezeket a különbségeket a vonatkozó nyelvi tervezési értekezlet (LDM) megjegyzései rögzítik.
A funkcióspektusok C# nyelvi szabványba való bevezetésének folyamatáról a specifikációkcímű cikkben olvashat bővebben.
Bajnoki probléma: https://github.com/dotnet/csharplang/issues/8374
Összefoglalás
A jobb konverziós szabályok frissítése annak érdekében, hogy konzisztensebben illeszkedjenek a params-hoz, és jobban kezeljék a jelenlegi kétértelműségi helyzeteket. A ReadOnlySpan<string> és a ReadOnlySpan<object> például jelenleg kétértelműséget okozhatnak a [""]túlterhelésének feloldásakor.
Részletes tervezés
Az alábbiakban a kifejezésszabályok jobb konvertálását mutatjuk be. Ezek váltják fel a szabályokat a https://github.com/dotnet/csharplang/blob/main/proposals/csharp-12.0/collection-expressions.md#overload-resolution-ban.
Ezek a szabályok a következők:
Egy kifejezésből
C₁Etípussá konvertáló implicit konverziósT₁és egy kifejezésbőlC₂típussáEkonvertáló implicit konverziósT₂C₁jobb konverziós, mintC₂, ha az alábbiak valamelyike fennáll:
Eegy gyűjteménykifejezés, ésC₁egy jobb gyűjteményátalakítás a kifejezés alapján, mintC₂.Enincs gyűjteménykifejezés, és az alábbiak egyike érvényes:
Epontosan egyezikT₁, ésEnem egyezik meg pontosanT₂Epontosan megegyezik, vagy mindkettővel, vagy egyikkel sem,T₁ésT₂közül, ésT₁jobb konverziós célpont, mintT₂Eegy metóduscsoport, ...
Új definíciót adunk hozzá jobb gyűjteményátalakításhoz a kifejezésből, az alábbiak szerint:
Adott:
- A
Eegy olyan gyűjteménykifejezés, amely[EL₁, EL₂, ..., ELₙ]elemkifejezéseket tartalmaz. -
T₁ésT₂gyűjteménytípusok -
E₁aT₁elemtípusa -
E₂aT₂elemtípusa - A(z)
CE₁ᵢa(z)ELᵢ-től a(z)E₁-ig tartó átalakulások sorozata. - A(z)
CE₂ᵢa(z)ELᵢ-től a(z)E₂-ig tartó átalakulások sorozata.
Ha identitásátalakítás történik E₁-ról E₂- ra, akkor az elemátalakítások ugyanolyan jók, mint egymás. Ellenkező esetben az elemek E₁ való konvertálása jobb, mintE₂, ha:
- Minden
ELᵢesetébenCE₁ᵢlegalább olyan jó, mintCE₂ᵢ, és - Van legalább egy i, ahol
CE₁ᵢjobb, mintCE₂ᵢEgyébként egyik elemátalakítás sem jobb, mint a másik, és ők sem olyan jók, mint egymás.
A konverziós összehasonlítások akkor készülnek jobb konverzióval a kifejezésből, haELᵢnem terjeszkedő elem. Ha aELᵢegy kibontott elem, akkor jobb átalakítást használunk a kibővített kollekció elemtípusárólE₁-re vagyE₂-re.
C₁ egy jobb gyűjteményátalakítás kifejezésből, mint C₂, ha:
- A
T₁és aT₂nem típusok, ésT₁implicit átalakíthatóT₂-re, mígT₂nem implicit átalakíthatóT₁-re, vagy -
E₁nem rendelkezik identitásátalakítássalE₂, és azE₁elemátalakítások jobbak, mint az-ra történőE₂elemátalakítások, vagy -
E₁-nak van egy identitáskonverziójaE₂-re, és az alábbiak egyike igaz:-
T₁System.ReadOnlySpan<E₁>,T₂pedigSystem.Span<E₂>, vagy -
T₁System.ReadOnlySpan<E₁>vagySystem.Span<E₁>, ésT₂egy elemtípusú tömb_vagy_tömbfelületE₂.
-
Ellenkező esetben egyik gyűjteménytípus sem jobb, és az eredmény nem egyértelmű.
Jegyzet
Ezek a szabályok azt jelentik, hogy az üres gyűjteménykifejezések esetében nem egyértelműek azok a módszerek, amelyek különböző elemtípusokat használó túlterheléseket fednek fel, és a gyűjteménytípusok közötti átalakítás nélkül. Példaként:
public void M(ReadOnlySpan<int> ros) { ... }
public void M(Span<int?> span) { ... }
M([]); // Ambiguous
Forgatókönyvek:
Egyszerű angol nyelven, maguknak a gyűjteménytípusoknak azonosnak vagy egyértelműen jobbnak kell lenniük (vagyis a List<T> és a List<T> azonosak, List<T> egyértelműen jobb, mint IEnumerable<T>, és List<T> és HashSet<T> nem lehet összehasonlítani), és a jobb gyűjteménytípus elemátalakításainak is azonosnak vagy jobbnak kell lenniük (azaz nem tudjuk eldönteni, hogy ReadOnlySpan<object> és Span<string> között [""], a felhasználónak meg kell hoznia ezt a döntést). További példák erre:
T₁ |
T₂ |
E |
C₁ Konverziók |
C₂ Konverziók |
CE₁ᵢ és CE₂ᵢ |
Eredmény |
|---|---|---|---|---|---|---|
List<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ a jobb választás |
List<int> van kiválasztva |
List<int> |
List<byte> |
[(int)1, (byte)2] |
[Identity, Implicit Numeric] |
Nem alkalmazható |
T₂ nem alkalmazható |
List<int> van kiválasztva |
List<int> |
List<byte> |
[1, (byte)2] |
[Identity, Implicit Numeric] |
[Implicit Constant, Identity] |
Egyik sem jobb | Félreérthető |
List<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ a jobb választás |
List<byte> van kiválasztva |
List<int?> |
List<long> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
Egyik sem jobb | Félreérthető |
List<int?> |
List<ulong> |
[1, 2, 3] |
[Implicit Nullable, Implicit Nullable, Implicit Nullable] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ a jobb választás |
List<int?> van kiválasztva |
List<short> |
List<long> |
[1, 2, 3] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
[Implicit Numeric, Implicit Numeric, Implicit Numeric] |
CE₁ᵢ a jobb választás |
List<short> van kiválasztva |
IEnumerable<int> |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ a jobb választás |
IEnumerable<int> van kiválasztva |
IEnumerable<int> |
List<byte> |
[(byte)1, (byte)2] |
[Implicit Numeric, Implicit Numeric] |
[Identity, Identity] |
CE₂ᵢ a jobb választás |
List<byte> van kiválasztva |
int[] |
List<byte> |
[1, 2, 3] |
[Identity, Identity, Identity] |
[Implicit Constant, Implicit Constant, Implicit Constant] |
CE₁ᵢ a jobb választás |
int[] van kiválasztva |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", "", ""] |
[Identity, Identity, Identity] |
[Implicit Reference, Implicit Reference, Implicit Reference] |
CE₁ᵢ a jobb választás |
ReadOnlySpan<string> van kiválasztva |
ReadOnlySpan<string> |
ReadOnlySpan<object> |
["", new object()] |
Nem alkalmazható | [Implicit Reference, Identity] |
T₁ nem alkalmazható |
ReadOnlySpan<object> van kiválasztva |
ReadOnlySpan<object> |
Span<string> |
["", ""] |
[Implicit Reference] |
[Identity] |
CE₂ᵢ a jobb választás |
Span<string> van kiválasztva |
ReadOnlySpan<object> |
Span<string> |
[new object()] |
[Identity] |
Nem alkalmazható |
T₁ nem alkalmazható |
ReadOnlySpan<object> van kiválasztva |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{1}"] |
[Interpolated String Handler] |
[Identity] |
CE₁ᵢ a jobb választás |
ReadOnlySpan<InterpolatedStringHandler> van kiválasztva |
ReadOnlySpan<InterpolatedStringHandler> |
ReadOnlySpan<string> |
[$"{"blah"}"] |
[Interpolated String Handler] |
[Identity] – De állandó |
CE₂ᵢ a jobb választás |
ReadOnlySpan<string> van kiválasztva |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}"] |
[Identity] |
[Interpolated String] |
CE₂ᵢ a jobb választás |
ReadOnlySpan<string> van kiválasztva |
ReadOnlySpan<string> |
ReadOnlySpan<FormattableString> |
[$"{1}", (FormattableString)null] |
Nem alkalmazható | [Interpolated String, Identity] |
T₁ nem alkalmazható |
ReadOnlySpan<FormattableString> van kiválasztva |
HashSet<short> |
Span<long> |
[1, 2] |
[Implicit Constant, Implicit Constant] |
[Implicit Numeric, Implicit Numeric] |
CE₁ᵢ a jobb választás |
HashSet<short> van kiválasztva |
HashSet<long> |
Span<short> |
[1, 2] |
[Implicit Numeric, Implicit Numeric] |
[Implicit Constant, Implicit Constant] |
CE₂ᵢ a jobb választás |
Span<short> van kiválasztva |
Kérdések megnyitása
Milyen mértékben rangsoroljuk a ReadOnlySpan/Span más típusokkal szemben?
A ma megadottak szerint a következő túlterhelések nem egyértelműek:
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> {}
Meddig akarunk idemenni? A List<T> változat ésszerűnek tűnik, és a List<T> altípusai bőségesen léteznek. De a HashSet verzió nagyon különböző szemantikával rendelkezik, mennyire vagyunk biztosak abban, hogy valójában "rosszabb", mint ReadOnlySpan ebben az API-ban?
C# feature specifications