Nezpracovaný řetězcový literál
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 příslušných 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/8647
Shrnutí
Umožněte novou formu řetězcového literálu, která začíná minimálně třemi znaky """
(ale bez maximálního omezení), volitelně následovaná znakem new_line
, obsahem řetězce a končí stejným počtem uvozovek, s jakým literál začal. Například:
var xml = """
<element attr="content"/>
""";
Vzhledem k tomu, že samotný vnořený obsah může chtít použít """
pak počáteční a koncové oddělovače můžou být delší, například takto:
var xml = """"
Ok to use """ here
"""";
Aby byl text snadno čitelný a umožňoval odsazení ve stylu, který vývojáři používají v kódu, tyto řetězcové literály při vytváření konečné hodnoty přirozeně odstraní odsazení z posledního řádku. Například literál formuláře:
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Bude mít obsah:
<element attr="content">
<body>
</body>
</element>
To umožňuje, aby kód vypadal přirozeně, přičemž stále vytváří požadované literály a vyhýbá se nákladům za běhu, pokud by to vyžadovalo použití speciálních rutin pro manipulaci s řetězci.
Pokud je chování odsazení nežádoucí, můžete ho jednoduše zakázat:
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Podporuje se také jednořádkový formulář. Začíná minimálně třemi """
znaky (ale bez maxima), obsahem řetězce (který nesmí obsahovat žádné new_line
znaky) a končí stejným počtem uvozovek, se kterým literál začal. Například:
var xml = """<summary><element attr="content"/></summary>""";
Podporují se také interpolované nezpracované řetězce. V tomto případě řetězec určuje počet složených závorek potřebných k zahájení interpolace (podle počtu znaků dolaru na začátku literálu). Jakákoli posloupnost závorek s menším počtem složených závorek, než je tento počet, je považována za obsah. Například:
var json = $$"""
{
"summary": "text",
"length" : {{value.Length}},
};
""";
Motivace
Jazyk C# nemá obecný způsob, jak vytvořit jednoduché řetězcové literály, které mohou efektivně obsahovat libovolný text. Všechny formuláře řetězcového literálu jazyka C# dnes potřebují nějakou formu escapingu pro případ, že obsah používá nějaký speciální znak (vždy, pokud se používá oddělovač). Tím zabráníte tomu, aby literály snadno obsahovaly prvky jiných jazyků (například XML, HTML nebo JSON literál).
Všechny aktuální přístupy k vytváření těchto literálů v jazyce C# dnes vždy nutí uživatele, aby manuálně uniknul obsah. Úpravy v tomto okamžiku mohou být velmi otravné, protože unikání nelze vyhnout a je třeba řešit při každém jeho vzniku v obsahu. To je obzvláště bolestné u regulárních výrazů, zejména pokud obsahují uvozovky nebo zpětné lomítka. I když používáte doslovný řetězec (@""
), uvozovky samy musí být uvozeny, což vede ke smíšení syntaxe jazyka C# a regulárních výrazů.
{
a }
jsou podobně frustrující v interpolovaných ($""
) řetězcích.
Crux problému spočívá v tom, že všechny naše řetězce mají pevný počáteční/koncový oddělovač. Pokud tomu tak je, budeme muset vždy mít eskapační mechanismus, protože obsah řetězce může potřebovat určit tento koncový oddělovač v jejich obsahu. To je obzvláště problematické, protože oddělovač "
je v mnoha jazycích velmi častý.
Tento návrh umožňuje flexibilní počáteční a koncové oddělovače, aby bylo možné je vždy provést způsobem, který nebude v konfliktu s obsahem řetězce.
Cíle
- Zadejte mechanismus, který uživateli umožní všechny řetězcové hodnoty, aniž by bylo nutné jakékoli řídicí sekvence. Vzhledem k tomu, že všechny řetězce musí být reprezentovatelné bez řídicích sekvencí, musí být vždy možné, aby uživatel určil oddělovače, které budou zaručeny, že nebudou kolidovat s žádným textovým obsahem.
- Podporujte interpolace stejným způsobem. Jak je uvedeno výše, protože všechny řetězce musí být reprezentovatelné bez escape sekvencí, musí být vždy možné, aby uživatel zadal oddělovač
interpolation
, který zaručeně nebude kolidovat s žádným textovým obsahem. Důležité je, že jazyky, které používají naši interpolaci oddělovače ({
a}
), by měly mít pocit, že je to prvotřídní a není to bolestné. - Víceřádkové řetězcové literály by měly v kódu vypadat příjemně a neměly by odsazení v jednotce kompilace vypadat divně. Důležité je, aby hodnoty literálů, které nemají žádné odsazení, nebyly nuceny zabírat první sloupec souboru, protože to může narušit tok kódu a bude to vypadat nesrovnaně se zbytkem kódu, který obklopuje.
- Toto chování by mělo být snadné přepsat, přičemž literály zůstávají jasné a snadno čitelné.
- U všech řetězců, které samy neobsahují
new_line
nebo začínají nebo končí znakem uvozovek ("
), by mělo být možné reprezentovat samotný řetězcový literál na jednom řádku.- Volitelně bychom to mohli upřesnit, abychom uvedli, že pro všechny řetězce, které samy o sobě neobsahují
new_line
(ale můžou začínat nebo končit uvozovkou"
), by mělo být možné reprezentovat řetězcový literál sám o sobě na jednom řádku. Další podrobnosti najdete v rozbaleném návrhu v částiDrawbacks
.
- Volitelně bychom to mohli upřesnit, abychom uvedli, že pro všechny řetězce, které samy o sobě neobsahují
Podrobný návrh (případ bez interpolace)
Přidáme novou string_literal
produkci s následující formou.
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>
;
Koncový oddělovač raw_string_literal
musí odpovídat počátečnímu oddělovači. Takže pokud je počáteční oddělovač """""
, musí být stejný i koncový oddělovač.
Výše uvedená gramatika raw_string_literal
by měla být interpretována takto:
- Začíná alespoň třemi uvozovkami (ale bez horní hranice uvozovek).
- Pak pokračuje obsahem na stejném řádku jako úvodní uvozovky. Tento obsah na stejném řádku může být prázdný nebo neprázdný. Prázdné je synonymem pro 'zcela bílé místo'.
- Pokud obsah na stejném řádku není prázdný, nebude možné sledovat další obsah. Jinými slovy literál musí na stejném řádku končit stejným počtem uvozovek.
- Pokud je obsah na stejném řádku prázdný, literál může pokračovat
new_line
a několika dalšími řádky obsahu anew_line
.- Řádek obsahu je jakýkoli text s výjimkou
new_line
. - Potom končí
new_line
nějaké číslo (pravděpodobně nula)whitespace
a stejný počet uvozovek, se kterými literál začal.
- Řádek obsahu je jakýkoli text s výjimkou
Nezpracovaná řetězcová literálová hodnota
Části mezi počátečním a koncovým raw_string_literal_delimiter
slouží k vytvoření hodnoty raw_string_literal
následujícím způsobem:
- V případě
single_line_raw_string_literal
bude hodnota literálu přesně obsahovat hodnoty mezi počátečním a koncovýmraw_string_literal_delimiter
. - V případě
multi_line_raw_string_literal
počátečníwhitespace* new_line
a poslednínew_line whitespace*
není součástí hodnoty řetězce. Poslední částwhitespace*
předcházející termináluraw_string_literal_delimiter
se považuje za mezeru odsazení a ovlivní interpretaci ostatních řádků. - Chcete-li získat konečnou hodnotu, prochází se posloupnost
(raw_content | new_line)*
a provede se následující:- Pokud je to
new_line
, obsahnew_line
se přidá do konečné řetězcové hodnoty. - Pokud není "prázdný"
raw_content
(tj.not_new_line+
obsahuje znak, který neníwhitespace
):- prázdný znak odsazení musí být předponou
raw_content
. V opačném případě se jedná o chybu. - Od začátku
raw_content
se odstraní odsazovací mezera a zbytek se přidá do konečné řetězcové hodnoty.
- prázdný znak odsazení musí být předponou
- Pokud se jedná o prázdnou
raw_content
(tj.not_new_line+
je zcelawhitespace
):- prázdný znak odsazení musí být předponou
raw_content
neboraw_content
musí být předponou prázdného znaku odsazení. V opačném případě se jedná o chybu. - pokud se od začátku
raw_content
odstraní velká část mezery pro odsazení a zbytek se přidá do konečné řetězcové hodnoty.
- prázdný znak odsazení musí být předponou
- Pokud je to
Objasnění:
single_line_raw_string_literal
není schopen reprezentovat řetězec, který obsahuje hodnotunew_line
.single_line_raw_string_literal
se ořezávání "odsazení prázdných znaků" nezúčastní. Jeho hodnota je vždy přesně ty znaky, které jsou mezi počátečními a koncovými oddělovači.Protože
multi_line_raw_string_literal
ignoruje konečnýnew_line
z posledního řádku obsahu, představuje následující řetězec bez počátečníhonew_line
a konečnéhonew_line
.
var v1 = """
This is the entire content of the string.
""";
To udržuje symetrii s tím, jak se počáteční new_line
ignoruje, a poskytuje také jednotný způsob, jak zajistit, aby bylo možné kdykoli upravit odsazení prázdných znaků. Chcete-li reprezentovat řetězec s terminálem new_line
musí být k dispozici řádek navíc, například:
var v1 = """
This string ends with a new line.
""";
single_line_raw_string_literal
nemůže reprezentovat řetězcovou hodnotu, která začíná nebo končí uvozovkou ("
), i když rozšíření tohoto návrhu je uvedené vDrawbacks
části, která ukazuje, jak by to mohlo být podporováno.Po počátečním
multi_line_raw_string_literal
whitespace* new_line
začíná sraw_string_literal_delimiter
. Tento obsah po oddělovači je zcela ignorován a není použit žádným způsobem při určování hodnoty řetězce. To umožňuje mechanismus určitraw_string_literal
, jehož obsah začíná samotným znakem"
. Například:
var v1 = """
"The content of this string starts with a quote
""";
-
raw_string_literal
může také představovat obsah, který končí uvozovkou ("
). Je to podporováno, protože ukončovací oddělovač musí být na vlastním řádku. Například:
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""
""";
- Požadavek, aby 'prázdný'
raw_content
byl buď předponou 'odsazení prázdných znaků', nebo aby 'odsazení prázdných znaků' bylo jeho předponou, pomáhá zabránit matoucím scénářům s různými typy prázdných znaků, zejména proto, že by tak nebylo jasné, co by se mělo s daným řádkem stát. Například následující případ je neplatný:
var v1 = """
Start
<tab>
End
""";
V této části je prázdné znaky odsazení devět znaků, ale prázdný
raw_content
nezačíná předponou. Neexistuje žádná jasná odpověď, jak by se měl<tab>
řádek vůbec zpracovávat. Měla by se ignorovat? Měla by být stejná jako.........<tab>
? Aby se předešlo nejasnostem, zdá se nejjednodušší, aby to bylo prohlášeno za nezákonné.Následující případy jsou sice právní a představují stejný řetězec:
var v1 = """
Start
<four spaces>
End
""";
var v1 = """
Start
<nine spaces>
End
""";
V obou těchto případech budou mezery odsazení tvořeny devíti mezerami. V obou případech odebereme co nejvíce z této předpony, což povede k tomu, že raw_content
bude v obou případech prázdný (nepočítaje každou new_line
). To uživatelům umožňuje, že při kopírování/vkládání nebo úpravách těchto řádků nemusí vidět mezery a případně si s nimi dělat starosti.
- V případě:
var v1 = """
Start
<ten spaces>
End
""";
Znaky prázdného místa pro odsazení budou stále devět mezer. V tomto případě však odebereme co nejvíce bílého znaku odsazení a symbol „prázdný“ raw_content
přidá do konečného obsahu jednu mezeru. To umožňuje případy, kdy obsah na těchto řádcích potřebuje prázdné znaky, které by se měly zachovat.
- Toto není technicky legální:
var v1 = """
""";
Důvodem je to, že začátek nezpracovaného řetězce musí mít new_line
(což má), ale konec musí mít také new_line
(což nemá). Minimální právní raw_string_literal
je:
var v1 = """
""";
Nicméně tento řetězec je rozhodně nezajímavý, protože je ekvivalentní ""
.
Příklady odsazení
Algoritmus "odsazení prázdných znaků" je možné vizualizovat na několika vstupech, jako je tomu tak. Následující příklady používají svislý znak pruhu |
k ilustraci prvního sloupce ve výsledném nezpracovaném řetězci:
Příklad 1 – standardní případ
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
interpretuje se jako
var xml = """
|<element attr="content">
| <body>
| </body>
|</element>
""";
Příklad 2 – Koncový oddělovač na stejném řádku jako obsah
var xml = """
<element attr="content">
<body>
</body>
</element>""";
Tohle je nezákonné. Poslední řádek obsahu musí končit new_line
.
Příklad 3 – Koncový oddělovač před počátečním oddělovačem
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
interpretuje se jako
var xml = """
| <element attr="content">
| <body>
| </body>
| </element>
""";
Příklad 4 – Konec oddělovače po počátečním oddělovači
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
Tohle je nezákonné. Řádky obsahu musí začínat prázdným znakem odsazení.
Příklad 5 – prázdný řádek
var xml = """
<element attr="content">
<body>
</body>
</element>
""";
interpretuje se jako
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Příklad 6 – prázdný řádek s menším prázdným znakem než předpona (tečky představují mezery)
var xml = """
<element attr="content">
<body>
</body>
....
</element>
""";
interpretuje se jako
var xml = """
|<element attr="content">
| <body>
| </body>
|
|</element>
""";
Příklad 7 – prázdný řádek s více prázdnými znaky než předpona (tečky představují mezery)
var xml = """
<element attr="content">
<body>
</body>
..............
</element>
""";
interpretuje se jako
var xml = """
|<element attr="content">
| <body>
| </body>
|....
|</element>
""";
Podrobný návrh (interpolační případ)
Interpolované výrazy v normálních interpolovaných řetězcích (např. $"..."
) jsou dnes podporovány pomocí znaku {
k zahájení prvku interpolation
a použití řídicí sekvence {{
k vložení skutečné otevřené závorky. Použití stejného mechanismu by porušilo cíle "1" a "2" tohoto návrhu. Jazyky, které mají {
jako základní znak (například JavaScript, JSON, Regex a dokonce vložený jazyk C#), by teď potřebovaly vytváření únikových sekvencí, čímž by ztratily účel surových řetězcových literálů.
Abychom podporovali interpolace, zavádíme je jiným způsobem, než jsou běžné $"
interpolované řetězce. Konkrétně interpolated_raw_string_literal
začne určitým počtem $
znaků. Počet těchto znaků udává, kolik znaků {
(a }
) je potřeba pro vymezení interpolation
v obsahu literálu. Důležité je, že nadále neexistuje žádný mechanismus pro escapování složených závorek. Stejně jako u uvozovek ("
) samotný literál může vždy zajistit, aby specifikoval oddělovače pro interpolace, které jsou jisté, že nekolidují s žádným zbytkem obsahu řetězce. Například literál JSON obsahující interpolační otvory se dá napsat takto:
var v1 = $$"""
{
"orders":
[
{ "number": {{order_number}} }
]
}
"""
V tomto případě {{...}}
odpovídá požadovanému počtu dvou složených závorek určených prefixem oddělovače $$
. V případě jednoho $
to znamená, že interpolace se zadává stejně jako {...}
jako v normálních interpolovaných řetězcových literálech. Důležité je, že interpolovaný literál s N
$
znaky může mít posloupnost 2*N-1
složených závorek (stejného typu za sebou). Posledních N
složených závorek spustí (nebo ukončí) interpolaci a zbývajících N-1
složených závorek bude jenom obsah. Například:
var v1 = $$"""X{{{1+1}}}Z""";
V tomto případě vnitřní dvě {{
a }}
složené závorky patří do interpolace, a vnější jednotlivé složené závorky jsou jen obsah. Výše uvedený řetězec je tedy ekvivalentní obsahu X{2}Z
. Použití 2*N
(nebo více) složených závorek je vždy chyba. Pokud chcete mít delší posloupnosti složených závorek jako obsah, je třeba odpovídajícím způsobem zvýšit počet znaků $
.
Interpolované řetězcové literály jsou definovány takto:
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.
;
Výše uvedené je podobné definici raw_string_literal
, ale s některými důležitými rozdíly.
interpolated_raw_string_literal
by se měla interpretovat takto:
- Začíná alespoň jedním znakem dolaru (ale bez horní hranice) a pak třemi uvozovkami (také bez horní hranice).
- Potom pokračuje textem na stejném řádku jako začínající uvozovky. Tento obsah na stejném řádku může být prázdný nebo neprázdný. Prázdné je synonymem pro 'zcela bílé místo'.
- Pokud obsah na stejném řádku není prázdný, nebude možné sledovat další obsah. Jinými slovy literál musí na stejném řádku končit stejným počtem uvozovek.
- Pokud je obsah na stejném řádku prázdný, literál může pokračovat
new_line
a několika dalšími řádky obsahu anew_line
.- Řádek obsahu je jakýkoli text s výjimkou
new_line
. - Řádek obsahu může na libovolné pozici obsahovat více výskytů
raw_interpolation
.raw_interpolation
musí začínat stejným počtem otevřených složených závorek ({
) jako je počet znaků dolaru na začátku literálu. - Pokud prázdné znaky odsazení nejsou prázdné,
raw_interpolation
nemůže okamžitě sledovatnew_line
. -
raw_interpolation
se bude řídit normálními pravidly uvedenými v §12.8.3. Každýraw_interpolation
musí končit stejným počtem uzavíracích závorek (}
) jako je počet znaků dolaru a otevřených složených závorek. - Každý
interpolation
může sám obsahovat nové řádky stejným způsobem jakointerpolation
v normálnímverbatim_string_literal
(@""
). - Potom končí
new_line
nějaké číslo (pravděpodobně nula)whitespace
a stejný počet uvozovek, se kterými literál začal.
- Řádek obsahu je jakýkoli text s výjimkou
Výpočet interpolované řetězcové hodnoty se řídí stejnými pravidly jako normální raw_string_literal
s výjimkou aktualizace pro zpracování řádků obsahujících raw_interpolation
s. Sestavení řetězcové hodnoty probíhá stejným způsobem, pouze s interpolačními otvory nahrazenými hodnotami, které tyto výrazy vytvářejí za běhu. Pokud je interpolated_raw_string_literal
převedena na FormattableString
pak se hodnoty interpolací předají v příslušném pořadí do pole arguments
do FormattableString.Create
. Zbytek obsahu interpolated_raw_string_literal
po"odsazení prázdných znaků" se použije k vygenerování řetězce format
předaného FormattableString.Create
s výjimkou odpovídajícím číslovaného {N}
obsahu v každém umístění, kde došlo k raw_interpolation
(nebo {N,constant}
v případě, že je jeho interpolation
formuláře expression ',' constant_expression
).
Ve výše uvedené specifikaci existuje nejednoznačnost. Konkrétně když část {
v textu a {
u interpolace sousedí. Například:
var v1 = $$"""
{{{order_number}}}
"""
To lze interpretovat jako: {{ {order_number } }}
nebo { {{order_number}} }
. Vzhledem k tomu, že první výraz je nelegální (žádný výraz jazyka C# nemůže začínat {
), by nemělo smysl to interpretovat tímto způsobem. Tak interpretujeme v druhém případě, kdy nejvnitřnější složené závorky {
a }
tvoří interpolaci a jakékoli nejvzdálenější tvoří text. V budoucnu to může být problém, pokud jazyk někdy podporuje jakékoli výrazy, které jsou obklopené složenými závorkami. V takovém případě by však bylo doporučení napsat takový případ takto: {{({some_new_expression_form})}}
. Zde by závorky pomohly označit výrazovou část od zbytku literálu nebo interpolace. To už má přednost s tím, jak ternární podmíněné výrazy musí být zabaleny, aby nebyly v konfliktu se specifikátorem formátování/zarovnání interpolace (např. {(x ? y : z)}
).
Nevýhody
Nezpracované řetězcové literály přidávají do jazyka větší složitost. Již máme mnoho řetězcových literálů pro různé účely.
""
řetězce, @""
řetězce a $""
řetězce už mají hodně výkonu a flexibility. Ale všechny nemají způsob, jak poskytnout nezpracovaný obsah, který nikdy nepotřebuje utéct.
Výše uvedená pravidla nepodporují případ 4.a:
- ...
- Volitelně bychom to mohli upřesnit, abychom uvedli, že pro všechny řetězce, které samy o sobě neobsahují
new_line
(ale můžou začínat nebo končit uvozovkou"
), by mělo být možné reprezentovat řetězcový literál sám o sobě na jednom řádku.
- Volitelně bychom to mohli upřesnit, abychom uvedli, že pro všechny řetězce, které samy o sobě neobsahují
To je proto, že nemáme žádné prostředky vědět, že počáteční nebo koncová uvozovka ("
) by měla patřit do obsahu, a ne samotný oddělovač. Pokud se jedná o důležitý scénář, který chceme podporovat, můžeme přidat paralelní '''
konstrukci, která bude sloužit spolu s formulářem """
. S tímto paralelním konstruktorem lze snadno zapsat řetězec s jedním řádkem, který začíná a končí "
, jako '''"This string starts and ends with quotes"'''
spolu s paralelním konstruktorem """'This string starts and ends with apostrophes'"""
. To může být také žádoucí pro vizuální oddělení uvozovkových znaků, což může pomoci při vkládání jazyků, které primárně používají jeden znak uvozovek mnohem častěji než druhý.
Alternativy
https://github.com/dotnet/csharplang/discussions/89 se zde zabývá mnoha možnostmi. Alternativy jsou četné, ale mám pocit, že se příliš zabývají složitostí a špatnou ergonomií. Tento přístup se rozhodne pro jednoduchost, kde prostě zvyšujete počáteční/koncovou délku uvozovek, dokud nehrozí konflikt s obsahem řetězce. Umožňuje také, aby kód, který napíšete, vypadal dobře odsazený, zatímco stále vytváří dedentovaný literál, který chce většina kódu.
Jednou z nejzajímavějších potenciálních variant je použití `
(nebo ```
) plotů pro tyto nezpracované řetězcové literály. To by mohlo mít několik výhod:
- Vyhne se všem problémům s řetězci, které začínají nebo končí uvozovkami.
- By vypadal povědomě jako Markdown. I když to samotné není možná dobrá věc, protože uživatelé můžou očekávat interpretaci Markdownu.
- Nezpracovaný řetězcový literál by ve většině případů musel začínat a končit pouze jedním znakem, a pouze v mnohem vzácnějším případě, kdy obsah sám obsahuje zpětné apostrofy, by bylo zapotřebí více znaků.
- Bylo by přirozené rozšířit to v budoucnu s
```xml
, opět podobně jako markdown. Samozřejmě, že to platí i pro"""
formulář.
Celkově se ale čistý přínos zdá malý. Vzhledem k historii jazyka C# myslím, že "
by měl být i nadále oddělovačem string literal
, stejně jako pro @""
a $""
.
Projektové schůzky
Otevřené problémy k prodiskutování Vyřešené problémy:
- [x] měli bychom mít jeden řádek formuláře? Technicky vzato bychom to bez toho mohli udělat. Ale to by znamenalo, že jednoduché řetězce, které neobsahují nový řádek, by vždy obsahovaly alespoň tři řádky. Myslím, že je zbytečně složité nutit konstrukce z jedné čáry do tří, jen abychom se vyhnuli escapování.
Rozhodnutí o návrhu: Ano, budeme mít jeden řádek formuláře.
- Měli bychom vyžadovat, aby víceřádkové musely začínat novým řádkem? Myslím, že bychom měli. Poskytuje nám také možnost podporovat věci, jako je
"""xml
v budoucnu.
Rozhodnutí o návrhu: Ano, budeme vyžadovat, aby víceřádkový text začínal novým řádkem.
- [x] Mělo by být automatické odsazení provedeno vůbec? Myslím, že bychom měli. Díky tomu bude kód vypadat mnohem příjemněji.
Rozhodnutí o návrhu: Ano, automatické odstranění bude provedeno.
- [x] Měli bychom omezit obyčejné mezery tak, aby se nekombinovaly různé typy mezer? Nemyslím si, že bychom měli. Existuje běžná strategie odsazování nazývaná "tabulátor pro odsazení, mezera pro zarovnání". Bylo by přirozené použít to k zarovnání koncového oddělovače s počátečním oddělovačem v případě, že počáteční oddělovač začíná mimo zarážku tabulátoru.
Rozhodnutí o návrhu: Nebudeme mít žádná omezení pro kombinování prázdných znaků.
- [x] měli bychom pro ploty použít něco jiného?
`
by odpovídala syntaxi markdownu a znamenalo by to, že bychom nemuseli tyto řetězce vždy začínat třemi uvozovkami. Stačí jen jeden pro běžný případ.
Rozhodnutí o návrhu: Použijeme """
- [x] Měli bychom mít požadavek, aby oddělovač měl více uvozovek než nejdelší posloupnost uvozovek v řetězcové hodnotě? Technicky vzato to není povinné. například:
var v = """
contents"""""
"""
Jedná se o řetězec s """
jako oddělovačem. Několik členů komunity uvedlo, že je to matoucí a v takovém případě bychom měli vyžadovat, aby oddělovač měl vždy více znaků. To by pak bylo:
var v = """"""
contents"""""
""""""
Rozhodnutí o návrhu: Ano, oddělovač musí být delší než jakákoli posloupnost uvozovek v samotném řetězci.
C# feature specifications