Dela via


UTF-8-strängar literaler

Anteckning

Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.

Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader återfinns i de relevanta LDM-anteckningarna (Language Design Meeting) .

Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.

Champion-problem: https://github.com/dotnet/csharplang/issues/184

Sammanfattning

Det här förslaget lägger till möjligheten att skriva UTF8-strängliteraler i C# och få dem automatiskt kodade i utf-8-byte representation.

Motivation

UTF8 är språket på webben och dess användning är nödvändig i betydande delar av .NET-stacken. Även om mycket av data kommer i form av byte[] utanför nätverksstacken finns det fortfarande betydande användning av konstanter i koden. Till exempel måste nätverksstacken ofta skriva konstanter som "HTTP/1.0\r\n", " AUTH" eller . "Content-Length: ".

Idag finns det ingen effektiv syntax för att göra detta eftersom C# representerar alla strängar med UTF16-kodning. Det innebär att utvecklare måste välja mellan bekvämligheten med kodning vid runtime, vilket innebär extra arbete, inklusive den tid som spenderas vid start för att faktiskt utföra kodningen (och allokeringar om typen inte faktiskt kräver dem), eller att manuellt översätta bytes och lagra i en byte[].

// 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 "));

Den här kompromissen är en smärtpunkt som ofta dyker upp för våra partners i runtime-miljön, ASP.NET och Azure. Ofta innebär det att de inte utnyttjar prestanda fullt ut eftersom de inte vill genomgå besväret med att skriva byte[]-kodningen för hand.

För att åtgärda detta tillåter vi UTF8-literaler på språket och kodar dem till UTF8-byte[] vid kompileringstillfället.

Detaljerad design

u8 suffix för strängliteraler

Språket tillhandahåller u8 suffixet för strängliteraler för att tvinga typen att vara UTF8. Suffixet är skiftlägesokänsligt, U8-suffix kommer att stödjas och ha samma betydelse som u8-suffix.

När u8-suffixet används är värdet för literalen en ReadOnlySpan<byte> som innehåller en UTF-8 byte-representation av strängen. En null-avslutare placeras utöver den sista byteen i minnet (och utanför längden på ReadOnlySpan<byte>) för att hantera vissa interop-scenarier där anropet förväntar sig null-avslutade strängar.

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>'.

Eftersom literalerna skulle allokeras som globala konstanter skulle livslängden för den resulterande ReadOnlySpan<byte> inte hindra att den returneras eller skickas runt till någon annanstans. Vissa kontexter, framför allt inom asynkrona funktioner, tillåter dock inte lokala variabler av ref-struktur, vilket innebär en prestandastraff i dessa situationer, där ett ToArray()-anrop eller liknande krävs.

En u8 literal har inget konstant värde. Det beror på att ReadOnlySpan<byte> inte kan vara typen av konstant idag. Om definitionen av const utökas i framtiden för att överväga ReadOnlySpan<byte>bör det här värdet också betraktas som en konstant. Praktiskt taget innebär detta att en u8 literal inte kan användas som standardvärde för en valfri parameter.

// Error: The argument is not constant
void Write(ReadOnlySpan<byte> message = "missing"u8) { ... } 

När indatatexten för literalen är en felaktigt formaterad UTF16-sträng genererar språket ett fel:

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.

Additionsoperator

En ny punkt läggs till i §12.10.5 Additionsoperator enligt följande.

  • SAMMANfogning av UTF8-byterepresentation:

    ReadOnlySpan<byte> operator +(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y);
    

    Den här binära +-operatorn utför sammanfogning av bytesekvenser och är applicerbar endast om båda operanderna är semantiskt representerade som UTF8-byte. En operand är semantiskt en UTF8-byte representation när det antingen är ett värde av en u8 literal eller ett värde som skapas av operatorn för UTF8-byte representationens sammankoppling.

    Resultatet av UTF8-byterepresentationens sammanlänkning är en ReadOnlySpan<byte> som består av bytena av den vänstra operanden följt av bytena av den högra operanden. En null-avslutare placeras utöver den sista byteen i minnet (och utanför längden på ReadOnlySpan<byte>) för att hantera vissa interop-scenarier där anropet förväntar sig null-avslutade strängar.

Sänka

Språket sänker UTF8-kodade strängar exakt som om utvecklaren hade skrivit den resulterande byte[] literal i kod. Till exempel:

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.

Det innebär att alla optimeringar som gäller för new byte[] { ... } formuläret även gäller för utf8-literaler. Det innebär att anropswebbplatsen blir allokeringsfri eftersom C# optimerar detta för att lagras i avsnittet .data i PE-filen.

Flera på varandra följande användningar av operatorer för sammanfogning av UTF8-bytepresentationer komprimeras till en enda skapelse av ReadOnlySpan<byte> med bytevektor som innehåller den slutliga bytesekvensen.

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.

Nackdelar

Förlita dig på kärn-API:er

Implementeringen av kompilatorn använder UTF8Encoding för både ogiltig strängidentifiering och översättning till byte[]. De exakta API:erna beror eventuellt på vilket målramverk kompilatorn använder. Men UTF8Encoding kommer att vara arbetshästen för implementeringen.

Tidigare har kompilatorn undvikit att använda runtime-API:er för literalbearbetning. Det beror på att det tar kontroll över hur konstanter bearbetas bort från språket och in i körningen. Konkret innebär det att objekt som felkorrigeringar kan ändra konstant kodning och innebär att resultatet av C#-kompileringen beror på vilken körning kompilatorn körs på.

Detta är inte ett hypotetiskt problem. Tidiga versioner av Roslyn använde double.Parse för att hantera parsning av flyttalskonstanter. Det orsakade ett antal problem. Först innebar det att vissa flyttalsvärden hade olika representationer mellan den inbyggda kompilatorn och Roslyn. För det andra, när .NET Core utvecklades och långvariga buggar i double.Parse-koden åtgärdades, innebar det att betydelsen av dessa konstanter förändrades i språket beroende på vilken körmiljö kompilatorn körde på. Därför skrev kompilatorn sin egen version av flyttalsparsningskoden och tog bort beroendet av double.Parse.

Det här scenariot diskuterades med runtime-teamet och vi anser inte att det har samma problem som vi har haft tidigare. UTF8-parsningen är stabil mellan körningar och det finns inga kända problem på det här området som är områden för framtida kompatibilitetsproblem. Om man kommer upp kan vi omvärdera strategin.

Alternativ

Endast måltyp

Designen kan förlita sig enbart på måltypning och ta bort u8-suffixet på string-literal. I de flesta fall i dag tilldelas string literal direkt till en ReadOnlySpan<byte> och därför är det onödigt.

ReadOnlySpan<byte> span = "Hello World;" 

Det u8-suffixet finns främst för att stödja två scenarier: var och överbelastningsupplösning. För de senare bör du överväga följande användningsfall:

void Write(ReadOnlySpan<byte> span) { ... } 
void Write(string s) {
    var bytes = Encoding.UTF8.GetBytes(s);
    Write(bytes.AsSpan());
}

Med tanke på implementeringen är det bättre att anropa Write(ReadOnlySpan<byte>) och u8 suffixet gör det här bekvämt: Write("hello"u8). När detta saknas behöver utvecklare ta till besvärliga typomvandlingar Write((ReadOnlySpan<byte>)"hello").

Det här är fortfarande en praktisk funktion, funktionen kan existera utan den och det är möjligt att lägga till den vid ett senare tillfälle.

Vänta på Utf8String-typen

Även om .NET-ekosystemet standardiseras på ReadOnlySpan<byte> som de facto Utf8-strängtyp för idag, är det möjligt att körtiden kommer att introducera en faktisk Utf8String-typ i framtiden.

Vi bör utvärdera vår design här inför den här möjliga ändringen och fundera på om vi skulle ångra de beslut vi har fattat. Detta bör dock vägas mot den realistiska sannolikheten vi kommer att införa Utf8String, en sannolikhet som verkar minska varje dag vi finner ReadOnlySpan<byte> som ett acceptabelt alternativ.

Det verkar osannolikt att vi skulle ångra måltypkonverteringen mellan strängliteraler och ReadOnlySpan<byte>. Användningen av ReadOnlySpan<byte> som utf8 är inbäddad i våra API:er nu och därför finns det fortfarande ett värde i konverteringen även om Utf8String kommer och är en "bättre" typ. Språket kan helt enkelt föredra konverteringar till Utf8String framför ReadOnlySpan<byte>.

Det verkar mer troligt att vi skulle ångra det u8 suffixet som pekar på ReadOnlySpan<byte> istället för Utf8String. Det skulle likna hur vi beklagar att stackalloc int[] har en naturlig typ av int* i stället för Span<int>. Detta är dock inte en avtalsbrytare, bara en olägenhet.

Konverteringar mellan string konstanter och byte sekvenser

Konverteringarna i det här avsnittet har inte implementerats. Dessa omvandlingar är fortfarande aktiva förslag.

Språket tillåter konverteringar mellan string konstanter och byte sekvenser där texten konverteras till motsvarande UTF8-byterepresentation. Specifikt tillåter kompilatorn string_constant_to_UTF8_byte_representation_conversion – implicita konverteringar från string konstanter till byte[], Span<byte>och ReadOnlySpan<byte>. En ny punktlista kommer att läggas till i avsnittet för implicita konverteringar §10.2. Denna konvertering är inte en standardkonvertering §10.4.

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 }

När indatatexten för konverteringen är en felaktigt formaterad UTF16-sträng genererar språket ett fel:

const string text = "hello \uD801\uD802";
byte[] bytes = text; // Error: the input string is not valid UTF16

Den dominerande användningen av den här funktionen förväntas vara med literaler, men den fungerar med alla string konstanta värden. En konvertering från en string konstant med null värde stöds också. Resultatet av konverteringen blir default värdet för måltypen.

const string data = "dog"
ReadOnlySpan<byte> span = data;     // new byte[] { 0x64, 0x6f, 0x67 }

När det gäller en konstant operation på strängar, till exempel +, sker kodningen till UTF8 på den sista string i stället för för de enskilda delarna och sedan sammanfoga resultaten. Den här ordningen är viktig att tänka på eftersom den kan påverka om konverteringen lyckas eller inte.

const string first = "\uD83D";  // high surrogate
const string second = "\uDE00"; // low surrogate
ReadOnlySpan<byte> span = first + second;

De två delarna här är ogiltiga på egen hand eftersom de är ofullständiga delar av ett surrogatpar. Individuellt finns det ingen korrekt översättning till UTF8 men tillsammans bildar de ett komplett surrogatpar som kan översättas till UTF8.

string_constant_to_UTF8_byte_representation_conversion tillåts inte i Linq-uttrycksträd.

Indata till dessa konverteringar är konstanter och data är helt kodade vid kompileringstillfället, men konverteringen inte anses konstant av språket. Det beror på att matriser inte är konstanta idag. Om definitionen av const expanderas i framtiden för att överväga matriser bör dessa konverteringar också beaktas. Praktiskt taget innebär detta att ett resultat av dessa konverteringar inte kan användas som standardvärde för en valfri parameter.

// Error: The argument is not constant
void Write(ReadOnlySpan<byte> message = "missing") { ... } 

När strängliteraler är implementerade har de samma problem som andra literaler har i språket: vilken typ de representerar beror på hur de används. C# tillhandahåller ett literalsuffix för att klargöra betydelsen för andra literaler. Utvecklare kan till exempel skriva 3.14f för att tvinga värdet att vara en float eller 1l för att tvinga värdet att vara en long.

Olösta frågor

De första tre designfrågorna gäller sträng till Span<byte> / ReadOnlySpan<byte> konverteringar. De har inte implementerats.

(Löst) Konverteringar mellan en string konstant med null värde och byte sekvenser

Om den här konverteringen stöds och i så fall hur den utförs anges inte.

förslag:

Tillåt implicita konverteringar från en string konstant med null värde till byte[], Span<byte>och ReadOnlySpan<byte>. Resultatet av konverteringen är default värdet för måltypen.

lösning:

Förslaget godkänns - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversions-from-null-literals.

(Löst) Var hör string_constant_to_UTF8_byte_representation_conversion hemma?

Är string_constant_to_UTF8_byte_representation_conversion en punkt i avsnittet om implicita konverteringar §10.2 ensam, eller är det en del av §10.2.11, eller tillhör den en annan befintlig grupp för implicita konverteringar?

förslag:

Det är en ny punkt i implicita konverteringar §10.2, liknande "Implicita interpolerade strängkonverteringar" eller "Metodgruppkonverteringar". Det känns inte som om det tillhör "Implicita konstanta uttryckskonverteringar" eftersom även om källan är ett konstant uttryck är resultatet aldrig ett konstant uttryck. Dessutom anses "Implicita konstanta uttryckskonverteringar" vara "implicita standardkonverteringar" §10.4.2, vilket sannolikt leder till icke-triviala beteendeändringar som involverar användardefinierade konverteringar.

lösning:

Vi introducerar en ny konverteringstyp för strängkonstant till UTF-8 byte – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-kinds

(Löst) Är string_constant_to_UTF8_byte_representation_conversion en standardomvandling

Förutom "rena" standardkonverteringar (standardkonverteringarna är de fördefinierade konverteringar som kan ske som en del av en användardefinierad konvertering) behandlar kompilatorn även vissa fördefinierade konverteringar som "något" standard. Till exempel kan en implicit interpolerad strängkonvertering ske som en del av en användardefinierad konvertering om det finns en explicit typomvandling till måltypen i koden. Som om det är en explicit standardkonvertering, även om det är en implicit konvertering som inte uttryckligen ingår i uppsättningen implicita eller explicita standardkonverteringar. Till exempel:

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();
}

förslag:

Den nya konverteringen är inte en standardkonvertering. Detta undviker icke-triviala beteendeändringar som involverar användardefinierade konverteringar. Vi behöver till exempel inte bekymra oss om användardefinierade cinversioner under implicita tuppellitralkonverteringar osv.

lösning:

Inte en standardkonvertering för tillfället – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#implicit-standard-conversion.

(Löst) Konvertering av linq-uttrycksträd

Ska string_constant_to_UTF8_byte_representation_conversion tillåtas i kontexten av en Linq Expression Tree-konvertering? Vi kan förbjuda det för tillfället, eller så kan vi helt enkelt inkludera den "sänkta" formen i trädet. Till exempel:

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})

Hur är det med strängliteraler med u8 suffix? Vi kan göra dem tillgängliga som byte-array-skapelser.

Expression<Func<byte[]>> x = () => "hello"u8;           // () => new [] {104, 101, 108, 108, 111}

lösning:

Tillåt inte i Linq Expression Trees – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#expression-tree-representation.

(Löst) Den naturliga typen av en strängliteral med suffixet u8

Avsnittet "Detaljerad design" säger: "Den naturliga typen kommer dock att vara ReadOnlySpan<byte>." Samtidigt: "När u8-suffixet används kan literalen fortfarande konverteras till någon av de tillåtna typerna: byte[], Span<byte> eller ReadOnlySpan<byte>."

Det finns flera nackdelar med den här metoden:

  • ReadOnlySpan<byte> är inte tillgängligt i skrivbordsramverket.
  • Det finns inga befintliga konverteringar från ReadOnlySpan<byte> till byte[] eller Span<byte>. För att stödja dem behöver vi förmodligen behandla literalerna som målskrivna. Både språkreglerna och implementeringen kommer att bli mer komplicerade.

förslag:

Den naturliga typen är byte[]. Den är lätt tillgänglig för alla ramverk. Förresten, under körning börjar vi alltid med att skapa en byte-array, även med det ursprungliga förslaget. Vi behöver inte heller några särskilda konverteringsregler för att stödja konverteringar till Span<byte> och ReadOnlySpan<byte>. Det finns redan implicita användardefinierade konverteringar från byte[] till Span<byte> och ReadOnlySpan<byte>. Det finns även implicit användardefinierad konvertering till ReadOnlyMemory<byte> (se frågan "Djup för konverteringen" nedan). Det finns en nackdel, språket tillåter inte kedjning av användardefinierade konverteringar. Följande kod kompileras därför inte:

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();
}

Men precis som med en användardefinierad konvertering kan en explicit typkonvertering användas för att göra en användardefinierad konvertering till en del av en annan användardefinierad konvertering.

Det känns som om alla motiverande scenarier kommer att hanteras med byte[] som naturlig typ, men språkreglerna och implementeringen kommer att vara betydligt enklare.

lösning:

Förslaget godkänns - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#natural-type-of-u8-literals. Vi kommer sannolikt att vilja ha en djupare debatt om huruvida u8 strängliteraler ska ha en typ av en föränderlig matris, men vi tror inte att den debatten är nödvändig för tillfället.

Endast den uttryckliga konverteringsoperatorn har implementerats.

(Löst) Djup för konverteringen

Kommer det också att fungera överallt där en byte[] kan fungera? Överväga:

static readonly ReadOnlyMemory<byte> s_data1 = "Data"u8;
static readonly ReadOnlyMemory<byte> s_data2 = "Data";

Det första exemplet bör troligen fungera på grund av den naturliga typen som kommer från u8.

Det andra exemplet är svårt att få att fungera eftersom det kräver konverteringar i båda riktningarna. Det är om vi inte lägger till ReadOnlyMemory<byte> som en av de tillåtna konverteringstyperna.

förslag:

Gör inget speciellt.

lösning:

Inga nya konverteringsmål har lagts till för tillfället https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-depth. Ingen av konverteringarna kompileras.

(Löst) Överbelastningsupplösningsavbrott

Följande API skulle bli tvetydigt:

M("");
static void M1(ReadOnlySpan<char> charArray) => ...;
static void M1(byte[] byteArray) => ...;

Vad ska vi göra för att åtgärda detta?

förslag:

I likhet med https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#overload-resolutionuppdateras Better function member (§11.6.4.3) till att föredra medlemmar där ingen av de konverteringar som ingår kräver konvertering string konstanter till UTF8 byte sekvenser.

Bättre funktionsmedlem

... Med tanke på en argumentlista A med en uppsättning argumentuttryck {E1, E2, ..., En} och två tillämpliga funktionsmedlemmar Mp och Mq med parametertyper {P1, P2, ..., Pn} och {Q1, Q2, ..., Qn}, definieras Mp som en bättre funktionsmedlem än Mq om

  1. för varje argument är den implicita konverteringen från Ex till Px inte en string_constant_to_UTF8_byte_representation_conversion, och för minst ett argument är den implicita konverteringen från Ex till Qx en string_constant_to_UTF8_byte_representation_conversion, eller
  2. för varje argument är den implicita konverteringen från Ex till Px inte en function_type_conversion, och
    • Mp är en icke-generisk metod eller Mp är en allmän metod med typparametrar {X1, X2, ..., Xp} och för varje typparameter Xi typargumentet härleds från ett uttryck eller från en annan typ än en function_type, och
    • för minst ett argument är den implicita konverteringen från Ex till Qx en function_type_conversion, eller Mq är en allmän metod med typparametrar {Y1, Y2, ..., Yq} och för minst en typparameter Yi typargumentet härleds från en function_type, eller
  3. för varje argument är den implicita konverteringen från Ex till Qx inte bättre än den implicita konverteringen från Ex till Px, och för minst ett argument är konverteringen från Ex till Px bättre än konverteringen från Ex till Qx.

Observera att tillägget av den här regeln inte kommer att omfatta scenarier där instansmetoder blir tillämpliga och skuggar tilläggsmetoderna. Till exempel:

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";
}

Beteendet för den här koden ändras tyst från att skriva ut "sträng" till att skriva ut "byte[]".

Är det okej med den här beteendeförändringen? Ska det dokumenteras som en icke-bakåtkompatibel ändring?

Observera att det inte finns något förslag om att göra string_constant_to_UTF8_byte_representation_conversion otillgänglig när C#10-språkversionen är riktad. I så fall blir exemplet ovan ett fel i stället för att återgå till C#10-beteendet. Detta följer en allmän princip om att målspråkversionen inte påverkar språkets semantik.

Är det okej med det här beteendet? Ska det dokumenteras som en icke-bakåtkompatibel ändring?

Den nya regeln kommer inte heller att förhindra avbrott som involverar tuppelns literalkonverteringar. Till exempel

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";
}

ska utan att meddela skriva ut "matris" i stället för "objekt".

Är det okej med det här beteendet? Ska det dokumenteras som en icke-bakåtkompatibel ändring? Vi kanske kan komplicera den nya regeln för att gräva i tuppelns literalkonverteringar.

lösning:

Prototypen kommer inte att justera några regler här, så vi kan förhoppningsvis se vad som går fel i praktiken - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#breaking-changes.

(Löst) Ska u8 suffix vara skiftlägesokänsligt?

förslag:

Stöd U8-suffix också för konsekvens med numeriska suffix.

lösning:

Godkänd – https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#suffix-case-sensitivity.

Exempel i dag

Exempel på var körtiden idag har kodat UTF8-byte manuellt

Exempel där vi lämnar perf i tabellen

Designa möten

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