Rå strängliteral
Not
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 fångas i de relevanta anteckningarna från Language Design Meeting (LDM) .
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/8647
Sammanfattning
Tillåt en ny form av strängliteral som börjar med minst tre """
tecken (men inget maxtecken), eventuellt följt av en new_line
, innehållet i strängen och slutar sedan med samma antal citattecken som literalen började med. Till exempel:
var xml = """
<element attr="content"/>
""";
Eftersom det kapslade innehållet kanske vill använda """
kan start-/slutavgränsarna vara längre så här:
var xml = """"
Ok to use """ here
"""";
För att göra texten lättläst och tillåta indrag som utvecklare gillar i kod tar dessa strängliteraler naturligt bort indraget som anges på den sista raden när du skapar det slutliga literalvärdet. Till exempel en literal av formuläret:
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Kommer att innehålla:
<element attr="content">
<body>
</body>
</element>
Detta gör att koden kan se naturlig ut, samtidigt som den producerar önskade literaler och undviker körningskostnader om detta kräver användning av specialiserade strängmanipuleringsrutiner.
Om indragsbeteendet inte är önskvärt är det också trivialt att inaktivera så här:
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Ett formulär med en rad stöds också. Det börjar med minst tre """
tecken (men inte maximalt), innehållet i strängen (som inte får innehålla några new_line
tecken) och slutar sedan med samma antal citattecken som literalen började med. Till exempel:
var xml = """<summary><element attr="content"/></summary>""";
Interpolerade råsträngar stöds också. I det här fallet anger strängen antalet klammerparenteser som behövs för att starta en interpolation (bestäms av antalet dollartecken som finns i början av literalen). En klammersekvens med färre klammer än så behandlas bara som innehåll. Till exempel:
var json = $$"""
{
"summary": "text",
"length" : {{value.Length}},
};
""";
Motivation
C# saknar ett allmänt sätt att skapa enkla strängliteraler som effektivt kan innehålla valfri godtycklig text. Alla C#-strängliterala formulär behöver i dag någon form av undflyende om innehållet använder ett specialtecken (alltid om en avgränsare används). Detta förhindrar att det är enkelt att ha literaler som innehåller andra språk i dem (till exempel en XML-, HTML- eller JSON-literal).
Alla aktuella metoder för att bilda dessa literaler i C# tvingar i dag alltid användaren att manuellt undkomma innehållet. Redigering vid den tidpunkten kan vara mycket irriterande eftersom flykten inte kan undvikas och måste hanteras när det uppstår i innehållet. Detta är särskilt smärtsamt för regexes, särskilt när de innehåller citattecken eller omvänt snedstreck. Även med en ordagrann (@""
) sträng måste citattecken själva escaperas, vilket resulterar i en blandning av C# och regex som blandas in.
{
och }
är lika frustrerande i interpolerade ($""
) strängar.
Kruxet med problemet är att alla våra strängar har en fast start/slut avgränsare. Så länge det är fallet måste vi alltid ha en flyktmekanism eftersom stränginnehållet kan behöva inkludera den slutliga avgränsaren i sitt innehåll. Detta är särskilt problematiskt eftersom avgränsare "
är mycket vanligt på många språk.
För att åtgärda detta möjliggör det här förslaget flexibla start- och slutavgränsare så att de alltid kan göras på ett sätt som inte står i konflikt med innehållet i strängen.
Mål
- Ange en mekanism som gör att alla strängvärden tillhandahålls av användaren utan att användaren behöver några escape-sekvenser. Eftersom alla strängar måste kunna representeras utan escape-sekvenser måste det alltid vara möjligt för användaren att ange avgränsare som garanterat inte kolliderar med något textinnehåll.
- Stöd för interpoleringar på samma sätt. Som ovan, eftersom alla strängar måste representeras utan escapes, måste användaren alltid ha möjlighet att ange en
interpolation
avgränsare som garanterat inte kolliderar med något textinnehåll. Det är viktigt att språk som använder vår interpolation avgränsartecken ({
och}
) ska kännas förstklassiga och inte smärtsamma att använda. - Flerradssträngliteraler bör se trevliga ut i kod och bör inte göra att indrag i kompileringsenheten ser konstigt ut. Det är viktigt att literala värden som i sig inte har någon indragning inte ska tvingas att uppta den första kolumnen i filen eftersom det kan bryta upp kodflödet och ser ojusterat ut jämfört med resten av koden som omger den.
- Det här beteendet bör vara enkelt att åsidosätta samtidigt som litterala uttryck är tydliga och lättlästa.
- För alla strängar som inte själva innehåller ett
new_line
eller börjar eller slutar med ett citattecken ("
) bör det vara möjligt att representera själva strängliteralen på en enda rad.- Valfritt, med ytterligare komplexitet, skulle vi kunna förfina detta för att ange att: För alla strängar som inte själva innehåller en
new_line
(men kan börja eller sluta med ett citattecken"
) ska det vara möjligt att representera hela strängliteralen på en enda rad. Mer information finns i det utökade förslaget i avsnittetDrawbacks
.
- Valfritt, med ytterligare komplexitet, skulle vi kunna förfina detta för att ange att: För alla strängar som inte själva innehåller en
Detaljerad design (icke-interpoleringsfall)
Vi lägger till en ny string_literal
-produktion med följande form.
string_literal
: regular_string_literal
| verbatim_string_literal
| raw_string_literal
;
raw_string_literal
: single_line_raw_string_literal
| multi_line_raw_string_literal
;
raw_string_literal_delimiter
: """
| """"
| """""
| etc.
;
raw_content
: not_new_line+
;
single_line_raw_string_literal
: raw_string_literal_delimiter raw_content raw_string_literal_delimiter
;
multi_line_raw_string_literal
: raw_string_literal_delimiter whitespace* new_line (raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
;
not_new_line
: <any unicode character that is not new_line>
;
Slutavgränsaren till en raw_string_literal
måste matcha den inledande avgränsaren. Så om startavgränsaren är """""
måste den avslutande avgränsare också vara det.
Grammatiken ovan för en raw_string_literal
ska tolkas som:
- Den börjar med minst tre citattecken (men ingen övre gräns för citattecken).
- Den fortsätter sedan med innehållet på samma rad som startcitaten. Innehållet på samma rad kan vara tomt eller inte tomt. "blank" är synonymt med "helt tomt utrymme".
- Om innehållet på samma rad inte är tomt kan inget ytterligare innehåll följa. Med andra ord ska literalen sluta med samma antal citat på samma rad.
- Om innehållet på samma rad är tomt kan literalen fortsätta med en
new_line
och ett antal efterföljande innehållsrader ochnew_line
s.- En innehållsrad är all text förutom en
new_line
. - Det avslutas sedan med ett
new_line
, ett antal (möjligen noll) avwhitespace
och samma antal citattecken som literalen började med.
- En innehållsrad är all text förutom en
Literalvärde för råsträng
Delarna mellan start och slut raw_string_literal_delimiter
används för att bilda värdet för raw_string_literal
på följande sätt:
- I fallet med
single_line_raw_string_literal
kommer värdet av literalen exakt att vara innehållet mellan början och slutet avraw_string_literal_delimiter
. - När det gäller
multi_line_raw_string_literal
, ingår den inledandewhitespace* new_line
och den sistanew_line whitespace*
inte i strängens värde. Den avslutandewhitespace*
-delen föreraw_string_literal_delimiter
-terminalen anses dock vara det 'blanksteg för indrag' och kommer att påverka hur de övriga raderna tolkas. - För att få fram det slutliga värdet genomgås sekvensen av
(raw_content | new_line)*
och följande utförs:- Om det är en
new_line
läggs innehållet inew_line
till i det slutliga strängvärdet. - Om det inte är en "tom"
raw_content
(dvs.not_new_line+
innehåller ett icke-whitespace
tecken):- tomt utrymme för indrag måste vara ett prefix för
raw_content
. Annars är det ett fel. - Indragningen av blankstecken tas bort från början av
raw_content
och den återstående delen läggs till i det slutliga strängvärdet.
- tomt utrymme för indrag måste vara ett prefix för
- Om det är en "tom"
raw_content
(dvs.not_new_line+
är heltwhitespace
):- blanksteget "indrag" måste vara ett prefix till
raw_content
eller så måsteraw_content
vara ett prefix till blanksteget "indrag". Annars är det ett fel. - så mycket av blanksteget "indrag" tas bort från början av
raw_content
och eventuella rester läggs till i det slutliga strängvärdet.
- blanksteget "indrag" måste vara ett prefix till
- Om det är en
Förtydliganden:
En
single_line_raw_string_literal
kan inte representera en sträng med ettnew_line
värde i den. Ensingle_line_raw_string_literal
deltar inte i trimningen av indragsutrymmet. Dess värde är alltid de exakta tecknen mellan start- och slutavgränsarna.Eftersom en
multi_line_raw_string_literal
ignorerar den sistanew_line
av den sista innehållsraden representerar följande en sträng utan startnew_line
och ingen avslutandenew_line
var v1 = """
This is the entire content of the string.
""";
Detta upprätthåller symmetrin med hur start-new_line
ignoreras, och det ger också ett enhetligt sätt att se till att "indragets blanksteg" alltid kan justeras. Om du vill representera en sträng med en terminal new_line
måste en extra rad anges så här:
var v1 = """
This string ends with a new line.
""";
En
single_line_raw_string_literal
kan inte representera ett strängvärde som börjar eller slutar med ett citattecken ("
) även om en förstoring av det här förslaget finns i avsnittetDrawbacks
som visar hur det kan stödjas.En
multi_line_raw_string_literal
börjar medwhitespace* new_line
efter den förstaraw_string_literal_delimiter
. Det här innehållet efter avgränsaren ignoreras helt och används inte på något sätt när värdet för strängen fastställs. På så sätt kan en mekanism ange enraw_string_literal
vars innehåll börjar med ett"
tecken. Till exempel:
var v1 = """
"The content of this string starts with a quote
""";
- En
raw_string_literal
kan också representera innehåll som slutar med ett citattecken ("
). Detta stöds eftersom den avslutande avgränsaren måste vara på sin egen rad. Till exempel:
var v1 = """
"The content of this string starts and ends with a quote"
""";
var v1 = """
""The content of this string starts and ends with two quotes""
""";
- Kravet att ett 'blankt'
raw_content
antingen måste vara ett prefix för 'indragets blanksteg' eller att 'indragets blanksteg' måste vara ett prefix för det, hjälper till att säkerställa att förvirrande scenarier med blandat blanksteg inte uppstår, särskilt eftersom det skulle vara oklart vad som ska ske med den raden. Följande fall är till exempel ogiltigt:
var v1 = """
Start
<tab>
End
""";
Här består "indragets blanksteg" av nio blankstegtecken, men "blank"
raw_content
börjar inte med detta som prefix. Det finns inget tydligt svar på hur den<tab>
linjen ska behandlas alls. Ska den ignoreras? Ska det vara samma som.........<tab>
? Att göra det olagligt verkar därför vara det tydligaste för att undvika förvirring.Följande fall är dock juridiska och representerar samma sträng:
var v1 = """
Start
<four spaces>
End
""";
var v1 = """
Start
<nine spaces>
End
""";
I båda dessa fall blir blanksteget "indrag" nio blanksteg. Och i båda fallen tar vi bort så mycket av prefixet som möjligt, vilket leder till att den tomma raw_content
i varje fall är tom (räknar inte varje new_line
). Detta gör att användarna inte behöver se och potentiellt oroa sig för blanksteg på dessa rader när de kopierar/klistrar in eller redigerar dessa rader.
- I fallet med:
var v1 = """
Start
<ten spaces>
End
""";
Tomt utrymme för indrag är fortfarande nio blanksteg. Här tar vi dock bort så mycket av "indragsutrymmet" som möjligt, och "blank" raw_content
kommer att bidra med ett enda mellanslag till det slutliga innehållet. Detta möjliggör fall där innehållet kräver blanksteg på dessa rader, som måste bevaras.
- Följande är tekniskt sett inte lagligt:
var v1 = """
""";
Det beror på att början av den råa strängen måste ha en new_line
(vilket den gör) men slutet måste också ha en new_line
(vilket den inte har). Den minimala juridiska raw_string_literal
är:
var v1 = """
""";
Den här strängen är dock avgjort ointressant eftersom den motsvarar ""
.
Indragsexempel
Algoritmen 'indrag vitrymd' kan visualiseras för flera indata på följande sätt. I följande exempel används det lodräta stapeltecknet |
för att illustrera den första kolumnen i den resulterande råsträngen:
Exempel 1 – Standardfall
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
tolkas som
var xml = """
|<element attr="content">
| <body>
| </body>
|</element>
""";
Exempel 2 – Avsluta avgränsare på samma rad som innehåll.
var xml = """
<element attr="content">
<body>
</body>
</element>""";
Det här är olagligt. Den sista innehållsraden måste sluta med en new_line
.
Exempel 3 – Slutavgränsare före startavgränsare
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
tolkas som
var xml = """
| <element attr="content">
| <body>
| </body>
| </element>
""";
Exempel 4 – Slutavgränsare efter startavgränsare
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Det här är olagligt. Innehållsraderna måste börja med blanksteget "indrag"
Exempel 5 – Tom rad
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
tolkas som
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Exempel 6 – Tom linje med mindre blanksteg än prefix (punkter representerar blanksteg)
var xml = """
<element attr="content">
<body>
</body>
....
</element>
""";
tolkas som
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Exempel 7 – Tom linje med mer blanksteg än prefix (punkter representerar blanksteg)
var xml = """
<element attr="content">
<body>
</body>
..............
</element>
""";
tolkas som
var xml = """
|<element attr="content">
| <body>
| </body>
|....
|</element>
""";
Detaljerad design (fall för interpolation)
Interpoleringar i normala interpolerade strängar (t.ex. $"..."
) stöds idag genom användning av tecknet {
för att initiera en interpolation
och användningen av en {{
escape-sekvens för att infoga ett verkligt öppnande klammerparentestecken. Att använda samma mekanism skulle strida mot målen "1" och "2" i detta förslag. Språk som har {
som ett kärntecken (exempel som JavaScript, JSON, Regex och till och med inbäddad C#) skulle nu behöva fly och ångra syftet med råa strängliteraler.
För att stödja interpoleringar introducerar vi dem på ett annat sätt än normalt $"
interpolerade strängar. Mer specifikt börjar en interpolated_raw_string_literal
med ett antal $
tecken. Antalet dessa anger hur många {
(och }
) tecken som behövs i innehållet i literalen för att avgränsa interpolation
. Det är viktigt att det fortfarande inte finns någon escapeing-mekanism för klammerparenteser. I stället, precis som med citattecken ("
) kan själva literalen alltid se till att den anger avgränsare för interpoleringar som säkert inte kolliderar med något av resten av innehållet i strängen. Till exempel kan en JSON-literal som innehåller interpolationshål skrivas så här:
var v1 = $$"""
{
"orders":
[
{ "number": {{order_number}} }
]
}
"""
Här matchar {{...}}
det nödvändiga antalet av två klammerparenteser som anges av avgränsaren $$
. När det gäller en enda $
innebär det att interpolationen anges precis som {...}
som i normala interpolerade strängliteraler. Viktigt är att detta innebär att en interpolerad literal med N
$
tecken kan ha en sekvens med 2*N-1
klammerparenteser (av samma typ i en rad). De sista N
klammerparenteserna startar (eller avslutar) en interpolering, och de återstående N-1
klammerparenteserna kommer bara att utgöra innehåll. Till exempel:
var v1 = $$"""X{{{1+1}}}Z""";
I det här fallet tillhör de två inre {{
och }}
klammerparenteser interpolationen, och de yttre enskilda klammerparenteserna utgör endast innehåll. Strängen ovan motsvarar därför innehållet X{2}Z
. Att ha 2*N
(eller fler) klammerparenteser är alltid ett fel. Om du vill ha längre sekvenser av klammerparenteser som innehåll måste antalet $
tecken ökas i enlighet med detta.
Interpolerade råsträngliteraler definieras som:
interpolated_raw_string_literal
: single_line_interpolated_raw_string_literal
| multi_line_interpolated_raw_string_literal
;
interpolated_raw_string_start
: $
| $$
| $$$
| etc.
;
interpolated_raw_string_literal_delimiter
: interpolated_raw_string_start raw_string_literal_delimiter
;
single_line_interpolated_raw_string_literal
: interpolated_raw_string_literal_delimiter interpolated_raw_content raw_string_literal_delimiter
;
multi_line_interpolated_raw_string_literal
: interpolated_raw_string_literal_delimiter whitespace* new_line (interpolated_raw_content | new_line)* new_line whitespace* raw_string_literal_delimiter
;
interpolated_raw_content
: (not_new_line | raw_interpolation)+
;
raw_interpolation
: raw_interpolation_start interpolation raw_interpolation_end
;
raw_interpolation_start
: {
| {{
| {{{
| etc.
;
raw_interpolation_end
: }
| }}
| }}}
| etc.
;
Ovanstående liknar definitionen av raw_string_literal
men med några viktiga skillnader. En interpolated_raw_string_literal
ska tolkas som:
- Det börjar med minst ett dollartecken (men ingen övre gräns) och sedan tre citattecken (också utan övre gräns).
- Den fortsätter sedan med innehåll på samma rad som de inledande citattecknaderna. Innehållet på samma rad kan vara tomt eller inte tomt. "blank" är synonymt med "helt tomt utrymme".
- Om innehållet på samma rad inte är tomt kan inget ytterligare innehåll följa. Med andra ord ska literalen sluta med samma antal citat på samma rad.
- Om innehållet på samma rad är tomt kan literalen fortsätta med en
new_line
och ett antal efterföljande innehållsrader ochnew_line
s.- En innehållsrad är all text förutom en
new_line
. - En innehållsrad kan innehålla flera
raw_interpolation
förekomster på valfri plats.raw_interpolation
måste börja med lika många öppna klammerparenteser ({
) som antalet dollartecken i början av literalen. - Om "blanksteg för indrag" inte är tomt kan en
raw_interpolation
inte omedelbart följa ennew_line
. -
raw_interpolation
följer de normala regler som anges i §12.8.3. Allaraw_interpolation
måste sluta med samma antal slutna klammerparenteser (}
) som dollartecken och öppna klammerparenteser. - Alla
interpolation
kan i sig innehålla nya rader på samma sätt som eninterpolation
i en normalverbatim_string_literal
(@""
). - Det avslutas sedan med ett
new_line
, ett antal (möjligen noll) avwhitespace
och samma antal citattecken som literalen började med.
- En innehållsrad är all text förutom en
Beräkningen av det interpolerade strängvärdet följer samma regler som en normal raw_string_literal
förutom uppdaterad för att hantera rader som innehåller raw_interpolation
s. Att skapa strängvärdet sker på samma sätt, bara med interpoleringshålen ersatta med de värden som uttrycken producerar vid körning. Om interpolated_raw_string_literal
konverteras till en FormattableString
skickas värdena av interpolationerna i respektive ordning till arguments
-matrisen till FormattableString.Create
. Resten av innehållet i interpolated_raw_string_literal
efter att "whitespace för indrag" har tagits bort från alla rader används för att generera format
strängen som skickas till FormattableString.Create
, förutom med lämpligt numrerat {N}
innehåll på varje plats där en raw_interpolation
inträffade (eller {N,constant}
om dess interpolation
är av formuläret expression ',' constant_expression
).
Det finns en tvetydighet i specifikationen ovan. Specifikt när en del av {
i text och {
av en interpolation kommer i kontakt med varandra. Till exempel:
var v1 = $$"""
{{{order_number}}}
"""
Detta kan tolkas som: {{ {order_number } }}
eller { {{order_number}} }
. Men eftersom det förstnämnda är olagligt (inget C#-uttryck kan börja med {
) skulle det vara meningslöst att tolka på det sättet. Så vi tolkar på det senare sättet, där de innersta {
och }
klammerparenteser bildar interpolationen, och alla yttersta bildar texten. I framtiden kan detta vara ett problem om språket någonsin har stöd för uttryck som omges av klammerparenteser. I så fall skulle rekommendationen dock vara att skriva ett sådant ärende så här: {{({some_new_expression_form})}}
. Här skulle parenteser hjälpa till att ange uttrycksdelen från resten av literalen/interpolationen. Detta har redan en överensstämmelse med hur ternära villkorsuttryck måste omslutas för att inte krocka med en interpolations formaterings-/justeringsspecifikation (t.ex. {(x ? y : z)}
).
Nackdelar
Råsträngliteraler lägger till mer komplexitet i språket. Vi har redan många strängliterala formulär redan för många syften.
""
strängar, @""
strängar och $""
strängar har redan mycket kraft och flexibilitet. Men de saknar alla ett sätt att tillhandahålla råinnehåll som aldrig behöver fly.
Ovanstående regler stöder inte fallet med 4.a:
- ...
- Valfritt, med ytterligare komplexitet, skulle vi kunna förfina detta för att ange att: För alla strängar som inte själva innehåller en
new_line
(men kan börja eller sluta med ett citattecken"
) ska det vara möjligt att representera hela strängliteralen på en enda rad.
- Valfritt, med ytterligare komplexitet, skulle vi kunna förfina detta för att ange att: För alla strängar som inte själva innehåller en
Det beror på att vi inte har något sätt att veta att ett start- eller slutcitat ("
) ska tillhöra innehållet och inte själva avgränsare. Om det här är ett viktigt scenario som vi vill stödja kan vi lägga till en parallell '''
-konstruktion för att motsvara """
-formen. Med den parallella konstruktionen kan en enda radsträng som startar och slutar med "
enkelt skrivas som '''"This string starts and ends with quotes"'''
tillsammans med den parallella konstruktionen """'This string starts and ends with apostrophes'"""
. Detta kan också vara önskvärt att stödja för att visuellt separera citattecken, vilket kan vara till hjälp när du bäddar in språk som främst använder ett citattecken mycket mer än det andra.
Alternativ
https://github.com/dotnet/csharplang/discussions/89 omfattar många alternativ här. Alternativen är många, men jag tycker att de avviker för långt in på komplexitet och för dålig ergonomi. Den här metoden väljer enkelhet där du bara fortsätter att öka citatlängden för start/slut tills det inte finns någon risk för en konflikt med stränginnehållet. Det gör också att koden du skriver ser väl indragen ut, samtidigt som den producerar en avindragen bokstavlig representation som är vad de flesta koder föredrar.
En av de mest intressanta potentiella variationerna är dock användningen av `
(eller ```
) avgränsare för dessa råsträngslitteraler. Detta skulle ha flera fördelar:
- Det skulle undvika alla problem med strängar som börjar eller slutar med citattecken.
- Det skulle se bekant ut som markdown. Även om det i sig inte är potentiellt bra eftersom användarna kan förvänta sig stöd för markdown.
- En rå strängliteral skulle bara behöva börja och sluta med ett enda tecken i de flesta fall, och skulle bara behöva flera i det mycket ovanligare fallet med innehåll som innehåller back-ticks själva.
- Det skulle kännas naturligt att utöka detta i framtiden med
```xml
, likt markdown. Även om det naturligtvis också gäller för den"""
formen.
På det hela taget verkar nettoförmånen här dock liten. I enlighet med C#-historiken tycker jag att "
bör fortsätta att vara den string literal
avgränsaren, precis som för @""
och $""
.
Designa möten
Öppna problem för att diskutera Lösta problem:
- [x] ska vi ha ett formulär med en rad? Vi skulle tekniskt sett klara oss utan det. Men det skulle innebära att enkla strängar som inte innehåller en ny rad alltid tar minst tre rader. Jag tycker att vi ska det är mycket tungviktare att tvinga enradskonstruktioner att vara tre linjer bara för att undvika att fly.
Designbeslut: Ja, vi kommer att ha ett formulär med en rad.
- [x] ska vi kräva att flerrads-måste börja med en ny rad? Jag tycker att vi borde göra det. Det ger oss också möjlighet att stödja saker som
"""xml
i framtiden.
Designbeslut: Ja, vi kommer kräva att flerradig text måste börja med en ny rad
- [x] bör den automatiska dedenteringen göras överhuvudtaget? Jag tycker att vi borde göra det. Det gör att koden ser så mycket trevligare ut.
Designbeslut: Ja, automatisk indragning kommer att göras.
- [x] bör vi begränsa common-whitespace från att blanda blankstegstyper? Jag tycker inte att vi ska göra det. Det finns faktiskt en gemensam indragsstrategi som kallas "tabb för indrag, mellanslag för justering". Det vore mycket naturligt att använda detta för att justera slutavgränsaren så att den stämmer överens med startavgränsaren i ett fall där startavgränsaren inte börjar vid ett tabbstopp.
Designbeslut: Vi kommer inte att ha några begränsningar för att blanda blanksteg.
- [x] ska vi använda något annat för stängslen?
`
skulle matcha markdown-syntaxen och skulle innebära att vi inte alltid behövde starta dessa strängar med tre citattecken. Bara en skulle räcka för det vanliga fallet.
Designbeslut: Vi använder """
- [x] bör vi ha ett krav på att avgränsaren har fler citattecken än den längsta sekvensen med citattecken i strängvärdet? Tekniskt sett krävs det inte. till exempel:
var v = """
contents"""""
"""
Det här är en sträng med """
som avgränsare. Flera communitymedlemmar har sagt att detta är förvirrande och vi bör kräva i ett fall som detta att avgränsare alltid har fler tecken. Det skulle då vara:
var v = """"""
contents"""""
""""""
Designbeslut: Ja, avgränsaren måste vara längre än någon sekvens med citattecken i själva strängen.
C# feature specifications