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.
Bajnok kérdés: https://github.com/dotnet/csharplang/issues/184
Összefoglalás
Ez a javaslat lehetővé teszi UTF8 sztringkonstansok írását C# nyelven, és automatikusan kódolja őket az UTF-8 byte ábrázolásába.
Motiváció
Az UTF8 a webes nyelv, használata pedig a .NET-verem jelentős részében szükséges. Bár az adatok nagy része a hálózati verem byte[] formájában érkezik, a kódban továbbra is jelentős állandók használatosak. A hálózati veremnek gyakran kell állandókat írnia, mint például "HTTP/1.0\r\n", " AUTH" vagy más hasonló értékeket.
"Content-Length: ".
Jelenleg nincs hatékony szintaxis erre, mivel a C# az UTF16 kódolást használó összes sztringet jelöli. Ez azt jelenti, hogy a fejlesztőknek választaniuk kell a futásidőben történő kódolás kényelme között, ami többletterhelést okoz, beleértve az indításkor a kódolási művelet tényleges végrehajtásával töltött időt (és a foglalásokat, ha olyan típust céloznak meg, amely valójában nem igényli őket), vagy manuálisan kell lefordítani a bájtokat, és egy byte[]tárolja őket.
// Efficient but verbose and error prone
static ReadOnlySpan<byte> AuthWithTrailingSpace => new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 };
WriteBytes(AuthWithTrailingSpace);
// Incurs allocation and startup costs performing an encoding that could have been done at compile-time
static readonly byte[] s_authWithTrailingSpace = Encoding.UTF8.GetBytes("AUTH ");
WriteBytes(s_authWithTrailingSpace);
// Simplest / most convenient but terribly inefficient
WriteBytes(Encoding.UTF8.GetBytes("AUTH "));
Ez a kompromisszum egy fájdalompont, amely gyakran jelentkezik partnereink számára a futtatókörnyezetben, ASP.NET és az Azure-ban. Gyakran előfordul, hogy kihagyják a lehetőségeiket, mert nem akarnak a byte[] kódolás kézzel történő leírásának nyűgén keresztülmenni.
Ennek kijavításához engedélyezzük az UTF8-literálok használatát a nyelvben, és lefordításkor az UTF8 byte[] kódoljuk őket.
Részletes kialakítás
u8 utótag karaktersorokon
A nyelv a u8 utótagot adja a sztring literálokhoz, hogy ezzel a típust UTF8-ra kényszerítse.
Az utótag nem érzékeny a kis- és nagybetűkre, a U8 utótagot támogatják, és ugyanazt a jelentést hordozza, mint a u8 utótag.
A u8 utótag használatakor a literál értéke egy ReadOnlySpan<byte>, amely a sztring UTF-8 bájtos ábrázolását tartalmazza.
A memóriában az utolsó bájton túl (és a ReadOnlySpan<byte>hosszán túl) egy null lezáró karakter van elhelyezve, hogy kezeljen néhány olyan interoperabilitási forgatókönyvet, ahol a hívás null lezárt karakterláncokat vár.
string s1 = "hello"u8; // Error
var s2 = "hello"u8; // Okay and type is ReadOnlySpan<byte>
ReadOnlySpan<byte> s3 = "hello"u8; // Okay.
byte[] s4 = "hello"u8; // Error - Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'byte[]'.
byte[] s5 = "hello"u8.ToArray(); // Okay.
Span<byte> s6 = "hello"u8; // Error - Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'System.Span<byte>'.
Mivel a konstansok globális állandókként lesznek lefoglalva, az eredményül kapott ReadOnlySpan<byte> élettartama nem akadályozná meg, hogy azokat vissza lehessen adni vagy máshová továbbadni. Bizonyos környezetek azonban, különösen az aszinkron függvényeken belül, nem teszik lehetővé az újrastrukturálási típusok helyi használatát, ezért ezekben a helyzetekben használati bírságot szabnának ki, ToArray() hívásra vagy hasonlóra van szükség.
A u8 literál nem rendelkezik állandó értékkel. Ennek az az oka, hogy ReadOnlySpan<byte> ma nem lehet az állandó típusa. Ha a const definíciója a jövőben ReadOnlySpan<byte>figyelembe adva bővül, akkor ezt az értéket is állandónak kell tekinteni. Gyakorlatilag ez azt jelenti, hogy egy u8 konstans nem használható az opcionális paraméterek alapértelmezett értékeként.
// Error: The argument is not constant
void Write(ReadOnlySpan<byte> message = "missing"u8) { ... }
Ha a literál bemeneti szövege hibásan formázott UTF16-sztring, akkor a nyelv hibát ad ki:
var bytes = "hello \uD8\uD8"u8; // Error: malformed UTF16 input string
var bytes2 = "hello \uD801\uD802"u8; // Allowed: invalid UTF16 values, but it's correctly formed.
Összeadás operátor
Az című, 12.10.5. §-ban meghatározott hozzáadási operátor részéhez az alábbiak szerint egy új listajelpont kerül hozzáadásra.
UTF8 bájtos ábrázolás összefűzés:
ReadOnlySpan<byte> operator +(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y);Ez a bináris
+operátor bájtütemezéseket hajt végre, és akkor és csak akkor alkalmazható, ha mindkét operandus szemantikailag UTF8 bájtos ábrázolás. Az operandus értelmezés szerint UTF8 bájtos ábrázolás, ha az érték egyu8literálé, vagy az UTF8 bájtos ábrázolás összefűzési operátor által előállított érték.Az UTF8 bájtábrázolás összefűzésének eredménye egy
ReadOnlySpan<byte>, amely tartalmazza a bal operand bájtjait, és ezt követik a jobb operand bájtjai. A memóriában az utolsó bájton túl (és aReadOnlySpan<byte>hosszán túl) egy null lezáró karakter van elhelyezve, hogy kezeljen néhány olyan interoperabilitási forgatókönyvet, ahol a hívás null lezárt karakterláncokat vár.
Csökkentés
A nyelv pontosan úgy alakítja kisbetűssé az UTF-8 kódolt sztringeket, mintha a fejlesztő az eredményül kapott byte[] literált írta volna a kódban. Például:
ReadOnlySpan<byte> span = "hello"u8;
// Equivalent to
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00 }).
Slice(0,5); // The `Slice` call will be optimized away by the compiler.
Ez azt jelenti, hogy az new byte[] { ... } űrlapra vonatkozó összes optimalizálás az utf8 literálokra is érvényes lesz. Ez azt jelenti, hogy a hívás helye allokációmentes lesz, mivel a C# úgy optimalizálja, hogy a PE-fájl .data szakaszában legyen tárolva.
A több egymást követő UTF8 bájtreprezentáció összefűző operátor alkalmazás egyetlen ReadOnlySpan<byte> létrehozására egyszerűsödik, amely a végső bájtsorozatot tartalmazó bájttömböt hoz létre.
ReadOnlySpan<byte> span = "h"u8 + "el"u8 + "lo"u8;
// Equivalent to
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00 }).
Slice(0,5); // The `Slice` call will be optimized away by the compiler.
Hátránya
Alapvető API-k használata
A fordító megvalósítása UTF8Encoding-t használ szövegértékeléshez és a byte[]-re történő fordításhoz is. A pontos API-k valószínűleg attól függenek, hogy a fordító melyik célkeretet használja. De UTF8Encoding lesz a megvalósítás munkacsoportja.
A fordító korábban elkerülte a futtatókörnyezeti API-k használatát a literális feldolgozáshoz. Ennek az az oka, hogy az állandók feldolgozása átkerül a nyelvről a futtatókörnyezetre. Konkrétan azt jelenti, hogy az olyan elemek, mint a hibajavítások, megváltoztathatják az állandó kódolást, és azt jelenti, hogy a C#-fordítás eredménye attól függ, hogy a fordító melyik futtatókörnyezetben hajt végre.
Ez nem hipotetikus probléma. A Roslyn korai verziói a lebegőpontos állandók elemzésére a double.Parse-t használták. Ez számos problémát okozott. Először azt jelentette, hogy néhány lebegőpontos értéknek eltérő ábrázolása volt a natív fordítóprogram és a Roslyn között. Másodszor, amikor a .NET Core kifejlődött, és kijavította a hosszú ideig fennálló hibákat a double.Parse kódban, azt jelentette, hogy az állandók jelentése megváltozott a nyelvben attól függően, hogy a fordító milyen futtatókörnyezetben hajtott végre. Ennek eredményeként a fordító végül megírta a lebegőpontos elemzési kód saját verzióját, és eltávolította a double.Parsefüggőségét.
Ezt a forgatókönyvet megvitattuk a futtatókörnyezeti csapattal, és nem érezzük, hogy ugyanazokkal a problémákkal járna, mint korábban. Az UTF8-elemzés különböző futásidőkben stabil, és ezen a területen nincsenek ismert problémák, amelyek a jövőbeni kompatibilitási aggályok tárgyát képezhetnék. Ha valaki mégis előjön, újra kiértékelhetjük a stratégiát.
Alternatívák
Csak céltípus
A terv csak a cél beírására támaszkodhat, és eltávolíthatja a u8 utótagot string literálokon. Az esetek többségében a string literál közvetlenül hozzá van rendelve egy ReadOnlySpan<byte>-hez, ami ezért szükségtelenné teszi.
ReadOnlySpan<byte> span = "Hello World;"
A u8 utótag elsősorban két forgatókönyvet támogat: a var és a túlterhelés feloldását. Az utóbbi esetében vegye figyelembe a következő használati esetet:
void Write(ReadOnlySpan<byte> span) { ... }
void Write(string s) {
var bytes = Encoding.UTF8.GetBytes(s);
Write(bytes.AsSpan());
}
A megvalósítás szerint jobb hívni a Write(ReadOnlySpan<byte>)-t, és a u8 utótag ezt megkönnyíti: Write("hello"u8). Ennek hiányában a fejlesztőknek kínos típuskényszerítéshez kell folyamodniuk Write((ReadOnlySpan<byte>)"hello").
Ez még mindig egy kényelmi elem, a funkció nélküle is létezhet, és nincs fennakadás, ha azt későbbi időpontban adja hozzá.
Várakozás az Utf8String típusra
Bár a .NET-ökoszisztéma ma már a ReadOnlySpan<byte>-t szabványosítja de facto UTF-8 karakterlánctípusként, lehetséges, hogy a futtatókörnyezet a jövőben ténylegesen bevezet majd egy Utf8String típust.
Értékeljük a tervünket a lehetséges változással szemben, és gondolkodjunk el azon, hogy sajnáljuk-e a meghozott döntéseket. Ezt mérlegelni kell annak a valószínűsége ellenére, hogy bevezetjük Utf8String, annak a valószínűsége, amely úgy tűnik, hogy csökken minden nap, amikor az ReadOnlySpan<byte> alternatívát elfogadhatónak találjuk.
Nem valószínű, hogy bánnánk a karakterlánc literálok és ReadOnlySpan<byte>közötti céltípus-átalakítást. Az ReadOnlySpan<byte> utf8-ként való használata most már beágyazva van az API-kba, így még mindig van érték az átalakításban, még akkor is, ha Utf8String jön, és egy "jobb" típus. A nyelv egyszerűen inkább átfordításokat választ Utf8String-ről ReadOnlySpan<byte>-ra.
Valószínűbbnek tűnik, hogy megbánnánk, ha a u8 utótag a ReadOnlySpan<byte>-re mutatna a Utf8Stringhelyett. Hasonló lenne ahhoz, ahogy sajnáljuk, hogy a stackalloc int[] természetes típusa int*, nem pedig Span<int>. Ez azonban nem egy komoly akadály, csak egy kellemetlenség.
Konverziók string állandók és byte sorozatok között
Az ebben a szakaszban szereplő átalakítások nincsenek implementálva. Ezek az átalakítások továbbra is aktív javaslatok maradnak.
A nyelv lehetővé teszi string konstansok és byte sorozatok közötti konvertálást, ahol a szöveg az egyenértékű UTF8 bájtos ábrázolássá alakul át. Pontosabban a fordító lehetővé teszi a string_constant_to_UTF8_byte_representation_conversion - implicit konverziókat string állandókból byte[], Span<byte>és ReadOnlySpan<byte>.
Az implicit konverziókhoz tartozó 10.2. § szakaszába új listajelpont lesz hozzáadva. Ez az §10.4átalakítás nem szabványos átalakítás.
byte[] array = "hello"; // new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f }
Span<byte> span = "dog"; // new byte[] { 0x64, 0x6f, 0x67 }
ReadOnlySpan<byte> span = "cat"; // new byte[] { 0x63, 0x61, 0x74 }
Ha az átalakítás bemeneti szövege helytelen formátumú UTF16-sztring, akkor a nyelv hibát ad ki:
const string text = "hello \uD801\uD802";
byte[] bytes = text; // Error: the input string is not valid UTF16
Ennek a funkciónak az elsődleges használata várhatóan literál értékekkel történik, de bármilyen string állandó értékkel fog működni.
A string konstansból null értékű átalakítás is támogatott lesz. Az átalakítás eredménye default céltípus értéke lesz.
const string data = "dog"
ReadOnlySpan<byte> span = data; // new byte[] { 0x64, 0x6f, 0x67 }
Sztringeken végzett bármilyen állandó művelet esetén, mint például a +, az UTF8 kódolás a végső string szintjén fog megtörténni, nem pedig az egyes részek esetében, amiket aztán összefűznek. Ezt a rendezést fontos figyelembe venni, mert hatással lehet arra, hogy az átalakítás sikeres-e.
const string first = "\uD83D"; // high surrogate
const string second = "\uDE00"; // low surrogate
ReadOnlySpan<byte> span = first + second;
Az itt található két rész önmagukban érvénytelen, mivel egy helyettesítő pár hiányos részei. Külön-külön nincs helyes fordítás az UTF8-ra, de együtt alkotnak egy teljes helyettesítő párt, amely sikeresen lefordítható az UTF8-ra.
A string_constant_to_UTF8_byte_representation_conversion nem megengedett a Linq kifejezésfákban.
Bár az ilyen konverziók bemenetei állandók, és az adatok fordítási időben teljesen kódolva vannak, a nyelv szerint az átalakítás nem tekinthető állandónak. Ennek az az oka, hogy a tömbök ma nem állandók. Ha a const definíciója a tömbök figyelembe osztása érdekében a jövőben bővül, akkor ezeket az átalakításokat is figyelembe kell venni. Gyakorlatilag ez azt jelenti, hogy ezeknek a konverzióknak az eredménye nem használható az opcionális paraméterek alapértelmezett értékeként.
// Error: The argument is not constant
void Write(ReadOnlySpan<byte> message = "missing") { ... }
A sztringkonstansok implementálása után ugyanaz a probléma jelentkezik, mint a többi literál a nyelvben: az általuk képviselt típus a használatuktól függ. A C# egy konstans utótagot biztosít a többi literál jelentésének egyértelműsítéséhez. A fejlesztők például megadhatják a 3.14f-t, hogy az érték float legyen, vagy a 1l-t, hogy az érték longlegyen.
Megoldatlan kérdések
Az első három tervezési kérdés a sztringek Span<byte> / ReadOnlySpan<byte> konverzióira vonatkozik. Ezeket még nem valósították meg.
(Megoldott) Konverziók string állandóval, amely null értékkel rendelkezik, és byte sorozatokkal
Azt, hogy ez az átalakítás támogatott-e, és ha igen, hogyan hajtja végre, nincs megadva.
javaslat:
Implicit átalakítások engedélyezése string konstans esetén null értékről byte[], Span<byte>és ReadOnlySpan<byte>típusokra. Az átalakítás eredménye a céltípus default értéke.
Felbontás:
A javaslatot jóváhagyták – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversions-from-null-literals.
(Megoldott) Hová tartozik a string_constant_to_UTF8_byte_representation_conversion?
Az implicit konverziók string_constant_to_UTF8_byte_representation_conversion§10.2 szakasz felsorolásjele, vagy §10.2.11része, vagy más meglévő implicit konverziós csoporthoz tartozik?
javaslat:
Ez egy új pont az implicit konverziókban, §10.2, hasonlóan az "Implicit interpolált string átalakításokhoz" vagy a "Metóduscsoport átalakításokhoz". Nem érzi úgy, hogy az "Implicit állandó kifejezés konverziói" közé tartozik, mert annak ellenére, hogy a forrás állandó kifejezés, az eredmény soha nem állandó kifejezés. Az "implicit konstanskifejezés-konverziók" is "Standard implicit konverzióknak" minősülnek, §10.4.2, ami valószínűleg nem triviális viselkedésbeli változásokhoz vezet a felhasználó által definiált konverziókkal.
Felbontás:
Bevezetünk egy új konverziós típust a szöveges állandók UTF-8 bájtra való átalakításához – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-kinds
(Megoldott) A(z) string_constant_to_UTF8_byte_representation_conversion szabványos átalakítás?
A "tiszta" standard konverziók mellett (a standard konverziók olyan előre definiált konverziók, amelyek egy felhasználó által definiált átalakítás részeként is előfordulhatnak), a fordító néhány előre definiált konverziót is "némileg" szabványként kezel. Az implicit interpolált sztringátalakítás például egy felhasználó által definiált átalakítás részeként történhet, ha a kódban explicit módon a céltípusra kerül sor. Mintha standard explicit konverzióról lenne szó, még akkor is, ha ez egy implicit konverzió, amely nem szerepel explicit módon a standard implicit vagy explicit konverziók készletében. Például:
class C
{
static void Main()
{
C1 x = $"hello"; // error CS0266: Cannot implicitly convert type 'string' to 'C1'. An explicit conversion exists (are you missing a cast?)
var y = (C1)$"dog"; // works
}
}
class C1
{
public static implicit operator C1(System.FormattableString x) => new C1();
}
javaslat:
Az új átalakítás nem szabványos átalakítás. Ez elkerüli a felhasználó által definiált konverziókat érintő nem triviális viselkedésváltozásokat. Például nem kell aggódnunk a felhasználó által definiált konverziók miatt az implicit tuple literális konverziók esetén, stb.
Felbontás:
Egyelőre nem szabványos átalakítás - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#implicit-standard-conversion.
(Megoldott) Linq Kifejezésfa konvertálása
Engedélyezni kell a string_constant_to_UTF8_byte_representation_conversion a Linq Expression Tree átalakítás kontextusában? Egyelőre letilthatjuk, vagy egyszerűen belefoglalhatjuk a "leengedett" formát a fába. Például:
Expression<Func<byte[]>> x = () => "hello"; // () => new [] {104, 101, 108, 108, 111}
Expression<FuncSpanOfByte> y = () => "dog"; // () => new Span`1(new [] {100, 111, 103})
Expression<FuncReadOnlySpanOfByte> z = () => "cat"; // () => new ReadOnlySpan`1(new [] {99, 97, 116})
Mi a helyzet a u8 utótaggal rendelkező sztringkonstansokkal? Ezeket bájttömbökként is létrehozhatjuk:
Expression<Func<byte[]>> x = () => "hello"u8; // () => new [] {104, 101, 108, 108, 111}
Felbontás:
Tiltás a Linq kifejezésfákban – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#expression-tree-representation.
(Megoldott) A karakterlánc-literál természetes típusa u8 utótaggal
A "Részletes tervezés" szakasz a következőt mondja: "A természetes típus azonban ReadOnlySpan<byte>." Ugyanakkor: "A u8 utótag használata esetén a literál továbbra is konvertálható az engedélyezett típusok bármelyikére: byte[], Span<byte> vagy ReadOnlySpan<byte>."
Ennek a megközelítésnek számos hátránya van:
-
ReadOnlySpan<byte>asztali keretrendszerben nem érhető el; - Nincsenek meglévő átalakítások
ReadOnlySpan<byte>-rólbyte[]-re vagySpan<byte>-re. A támogatásukhoz valószínűleg céltípusként kell kezelni a literálokat. A nyelvi szabályok és a megvalósítás is egyre bonyolultabbá válik.
javaslat:
A természetes típus byte[]lesz. Minden keretrendszerben könnyen elérhető. BTW, futásidőben mindig egy bájttömb létrehozásával kezdjük, még az eredeti javaslattal is. A Span<byte> és ReadOnlySpan<byte>konvertálásának támogatásához nincs szükség speciális konverziós szabályokra. Már vannak implicit, felhasználó által definiált átalakítások byte[]-ról Span<byte>-ra és ReadOnlySpan<byte>. Még implicit, felhasználó által definiált átalakítás is létezik a ReadOnlyMemory<byte>-hoz (lásd az alábbi "Az átalakítás mélysége" kérdést). Van egy hátránya, a nyelv nem teszi lehetővé a felhasználó által definiált konverziók láncolását. A következő kód tehát nem fog lefordulni:
using System;
class C
{
static void Main()
{
var y = (C2)"dog"u8; // error CS0030: Cannot convert type 'byte[]' to 'C2'
var z = (C3)"cat"u8; // error CS0030: Cannot convert type 'byte[]' to 'C3'
}
}
class C2
{
public static implicit operator C2(Span<byte> x) => new C2();
}
class C3
{
public static explicit operator C3(ReadOnlySpan<byte> x) => new C3();
}
Azonban, mint minden felhasználó által definiált átalakításnál, egy explicit kasztolás is használható arra, hogy egy felhasználó által definiált átalakítás egy másik felhasználó által definiált átalakítás része legyen.
Úgy tűnik, hogy minden motiváló forgatókönyvet természetes típusként byte[] fognak kezelni, de a nyelvi szabályok és a megvalósítás jelentősen egyszerűbb lesz.
Felbontás:
A javaslatot jóváhagyták – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#natural-type-of-u8-literals.
Valószínűleg részletesebb vitát szeretnénk majd arról, hogy a u8 karakterlánc-literáloknak módosítható tömb típussal kell-e rendelkezniük, de ezt a vitát egyelőre nem tartjuk szükségesnek.
Csak a explicit konverziós operátor lett implementálva.
(Megoldott) Az átalakítás mélysége
Működni fog olyan helyeken is, ahol bájt[] használható? Tekint:
static readonly ReadOnlyMemory<byte> s_data1 = "Data"u8;
static readonly ReadOnlyMemory<byte> s_data2 = "Data";
Az első példa valószínűleg működik, mert a természetes típus a u8-ból származik.
A második példa nehezen használható, mert mindkét irányban konverziót igényel. Ez hacsak nem tesszük hozzá a ReadOnlyMemory<byte>-t az engedélyezett konverziós típusok közé.
javaslat:
Ne csináld semmi különlegeset.
Felbontás:
Egyelőre nem adtak hozzá új konverziós célokat https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-depth. Egyik konverzió sem fordul le.
(Megoldott) Túlterhelés feloldási hibák
A következő API nem egyértelmű:
M("");
static void M1(ReadOnlySpan<char> charArray) => ...;
static void M1(byte[] byteArray) => ...;
Mit tegyünk, hogy ezt megoldjuk?
javaslat:
A https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#overload-resolution-hez hasonlóan a Better függvénytag (§11.6.4.3) frissül, hogy előnyben részesítse azokat a tagokat, akiknél az átalakítások egyike sem igényli string konstansok UTF8 byte sorozattá alakítását.
Jobb függvénytag
... A
Aés{E1, E2, ..., En}paramétertípusúMpésMqargumentumkifejezésekkel{P1, P2, ..., Pn}{Q1, Q2, ..., Qn}és két alkalmazható függvénytagot tartalmazó argumentumlistaMpjobb függvény tagként van definiálva, mintMq
- az egyes argumentumok esetében az
Ex-rőlPx-ra történő implicit átalakítás nem egy string_konstans_UTF8_bájt_reprezentáció_átalakítás, és legalább egy argumentum esetében azEx-rőlQx-ra történő implicit átalakítás egy string_konstans_UTF8_bájt_reprezentáció_átalakításvagy- az egyes argumentumok esetében a
Ex-rőlPx-re történő implicit átalakítás nem függvénytípus-átalakítás, és
Mpnem generikus metódus, vagyMpolyan generikus metódus, amely a{X1, X2, ..., Xp}típusparamétereket tartalmazza, és minden egyesXitípusparaméterhez a típusargumentum egy kifejezésből vagy egy másik, nem függvénytípustípusból származik, és- Legalább egy argumentum esetében a
Ex-rőlQx-ra való implicit átalakítás egy függvénytípus-átszámítás, vagyMqegy általános metódus, amely típusparamétereket tartalmaz{Y1, Y2, ..., Yq}, és legalább egy típusparaméter esetébenYia típusargumentum egy függvénytípusbólvan levezetve, vagy- minden argumentum esetében az
ExésQxközötti implicit átalakítás nem jobb, mint aExésPxközötti implicit átalakítás, és legalább egy argumentum esetében aEx-rőlPx-ra való átalakítás jobb, mint aEx-rólQx- ra történő átalakítás.
Vegye figyelembe, hogy a szabály hozzáadása nem fogja lefedni azokat a forgatókönyveket, amelyekben a példánymetodusok alkalmazhatóvá válnak, és "árnyékoló" kiterjesztési módszereket használnak. Például:
using System;
class Program
{
static void Main()
{
var p = new Program();
Console.WriteLine(p.M(""));
}
public string M(byte[] b) => "byte[]";
}
static class E
{
public static string M(this object o, string s) => "string";
}
A kód viselkedése csendesen megváltozik a "sztring" nyomtatásáról a "bájt[]" nyomtatásra.
Rendben vagyunk ezzel a viselkedésváltozással? Kompatibilitástörő változásként kell dokumentálni?
Vegye figyelembe, hogy a C#10 nyelvi verzió célba vételekor nincs javaslat arra, hogy a string_constant_to_UTF8_byte_representation_conversion elérhetetlenné váljon. Ebben az esetben a fenti példa hibává válik, ahelyett, hogy visszatérne a C#10-viselkedésre. Ez egy általános alapelvet követ, amely szerint a célnyelvi verzió nem befolyásolja a nyelv szemantikáját.
Rendben vagyunk ezzel a viselkedéssel? Kompatibilitástörő változásként kell dokumentálni?
Az új szabály sem fogja megakadályozni a tuple literális konverziók töréseit. Például
class C
{
static void Main()
{
System.Console.Write(Test(("s", 1)));
}
static string Test((object, int) a) => "object";
static string Test((byte[], int) a) => "array";
}
Csendben a "tömb" szót fogja kinyomtatni az "objektum" helyett.
Rendben vagyunk ezzel a viselkedéssel? Kompatibilitástörő változásként kell dokumentálni? Talán bonyolíthatnánk az új szabályt, hogy beleássunk a tupelliterál konverziójába.
Felbontás:
A prototípus itt nem módosítja a szabályokat, így remélhetőleg láthatjuk, mi romlik el a gyakorlatban - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#breaking-changes.
(Megoldott) Legyen a u8 utótag kis- és nagybetűre érzéketlen?
javaslat:
Támogassa a U8 utótagot is, hogy konzisztens legyen a numerikus utótagokkal.
Felbontás:
Jóváhagyva – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#suffix-case-sensitivity.
Példák ma
Példák arra, hogy a futtatókörnyezet ma manuálisan kódolja az UTF8 bájtokat
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/StatusCodes.cs#L13-L78
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Memory/src/System/Buffers/Text/Base64Encoder.cs#L581-L591
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStream.Windows.cs#L284
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs#L30
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs#L852
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs#L35-L42
Példák arra, hogy hol hagyjuk a perf-et a táblán
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeChannelBindingHandle.cs#L16-L17
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs#L37-L43
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L78
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpCommands.cs#L669-L687
Tervezési értekezletek
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-18.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-06-06.md
C# feature specifications