Delen via


Letterlijke onbewerkte tekenreeks

Notitie

Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.

Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. Deze verschillen worden vastgelegd in de relevante notities van de Language Design Meeting (LDM) .

Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.

Samenvatting

Sta een nieuwe vorm van tekenreeks-literal toe die begint met minimaal drie """-tekens (maar geen maximum), optioneel gevolgd door een new_line, de inhoud van de tekenreeks, en eindigt vervolgens met hetzelfde aantal aanhalingstekens als waarmee de tekenreeks-literal begon. Bijvoorbeeld:

var xml = """
          <element attr="content"/>
          """;

Omdat de geneste inhoud mogelijk zelf """ wil gebruiken, kunnen de beginnende/eindigende afscheidingstekens langer zijn:

var xml = """"
          Ok to use """ here
          """";

Om de tekst gemakkelijk leesbaar te maken en de inspringing die ontwikkelaars prettig vinden in code mogelijk te maken, zullen deze letterlijke tekenreeksen de inspringing die op de laatste regel is aangegeven, automatisch verwijderen bij het produceren van de uiteindelijke letterlijke waarde. Bijvoorbeeld een letterlijke notatie van het formulier:

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

Bevat de inhoud:

<element attr="content">
  <body>
  </body>
</element>

Hierdoor kan code er natuurlijk uitzien, terwijl gewenste letterlijke waarden worden geproduceerd en runtimekosten worden vermeden, als het gebruik van gespecialiseerde routines voor tekenreeksmanipulatie nodig zou zijn.

Als het inspringingsgedrag niet gewenst is, is het ook triviaal om dit uit te schakelen:

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

Een formulier met één regel wordt ook ondersteund. Het begint met een minimum van drie """ tekens (maar geen maximum), de inhoud van de tekenreeks (die geen new_line tekens mag bevatten) en eindigt vervolgens met hetzelfde aantal aanhalingstekens waarmee het letterlijk begon. Bijvoorbeeld:

var xml = """<summary><element attr="content"/></summary>""";

Geïnterpoleerde onbewerkte tekenreeksen worden ook ondersteund. In dit geval geeft de tekenreeks het aantal accolades op dat nodig is om een interpolatie te starten (bepaald door het aantal dollartekens dat aanwezig is aan het begin van de letterlijke tekst). Elke accoladereeks met minder accolades dan dat wordt gewoon als inhoud gezien. Bijvoorbeeld:

var json = $$"""
             {
                "summary": "text",
                "length" : {{value.Length}},
             };
             """;

Motivatie

C# mist een algemene manier om eenvoudige letterlijke tekenreeksen te maken die in feite willekeurige tekst kunnen bevatten. Alle letterlijke C#-tekenreeksen hebben tegenwoordig een vorm van escape nodig als de inhoud een speciaal teken gebruikt (altijd als er een scheidingsteken wordt gebruikt). Dit voorkomt gemakkelijk dat literalen andere talen bevatten (zoals een XML-, HTML- of JSON-literalen).

Alle huidige benaderingen om deze letterlijke waarden in C# te vormen, dwingen de gebruiker altijd handmatig te ontsnappen aan de inhoud. Bewerken op dat moment kan zeer vervelend zijn omdat het ontsnappen niet kan worden vermeden en moet worden behandeld wanneer het zich in de inhoud voordoet. Dit is bijzonder pijnlijk voor regexes, vooral wanneer ze aanhalingstekens of backslashes bevatten. Zelfs met een letterlijke tekenreeks (@""), moeten de aanhalingstekens zelf worden geëscapet, wat leidt tot een mix van C# en regex. { en } zijn vergelijkbaar frustrerend in geïnterpoleerde tekenreeksen ($"").

De crux van het probleem is dat al onze tekenreeksen een vast scheidingsteken voor begin/eind hebben. Zolang dat het geval is, moeten we altijd een escapemechanisme hebben, omdat de inhoud van de tekenreeks mogelijk dat eindscheidingsteken in de inhoud moet worden opgegeven. Dit is met name problematisch omdat het scheidingsteken " in veel talen zeer gebruikelijk is.

Om dit te verhelpen, biedt dit voorstel flexibele begin- en eindscheidingstekens, zodat ze altijd op een manier kunnen worden gemaakt die niet conflicteert met de inhoud van de tekst.

Doelen

  1. Geef een mechanisme op waarmee alle tekenreekswaarden door de gebruiker kunnen worden verstrekt zonder dat escape-reeksen hoeft te worden gebruikt. Omdat alle tekenreeksen zonder escape-reeksen moeten worden weergegeven, moet de gebruiker altijd scheidingstekens kunnen opgeven die gegarandeerd niet botsen met tekstinhoud.
  2. Ondersteun interpolaties op dezelfde wijze. Zoals hierboven, omdat alle tekenreeksen moeten worden weergegeven zonder escapes, moet het altijd mogelijk zijn voor de gebruiker om een interpolation scheidingsteken op te geven dat gegarandeerd niet botst met tekstinhoud. Belangrijk: talen die gebruikmaken van onze interpolatie scheidingstekens ({ en }) moeten zich eersteklas voelen en niet pijnlijk om te gebruiken.
  3. Letterlijke tekenreeksen met meerdere regels moeten er prettig uitzien in code en mogen de inspringing binnen de compilatie-eenheid niet vreemd maken. Belangrijk is dat letterlijke waarden die zelf geen inspringing hebben, niet moeten worden gedwongen om de eerste kolom van het bestand te bezetten, omdat deze de stroom van code kan opsplitsen en er niet uitgelijnd uitziet met de rest van de code eromheen.
    • Dit gedrag moet gemakkelijk te overschrijven zijn, terwijl letterlijke gegevens duidelijk en gemakkelijk te lezen blijven.
  4. Voor alle tekenreeksen die niet zelf een new_line of begin of einde met een aanhalingsteken (") bevatten, moet het mogelijk zijn om de letterlijke tekenreeks op één regel weer te geven.
    • Optioneel, met extra complexiteit, zouden we dit kunnen verfijnen om aan te geven dat: Voor alle tekenreeksen die zelf geen new_line bevatten (maar wel kunnen beginnen of eindigen met een aanhalingsteken "), het mogelijk moet zijn om de letterlijke tekenreeks op één regel te zetten. Zie het uitgebreide voorstel in de sectie Drawbacks voor meer informatie.

Gedetailleerd ontwerp (niet-interpolatiegeval)

We voegen een nieuwe string_literal productie toe met de volgende vorm:

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

Het eindscheidingsteken voor een raw_string_literal moet overeenkomen met het beginscheidingsteken. Dus als het beginscheidingsteken """"" is, moet het eindscheidingsteken ook die zijn.

De bovenstaande grammatica voor een raw_string_literal moet worden geïnterpreteerd als:

  1. Het begint met ten minste drie aanhalingstekens (maar geen bovengrens voor aanhalingstekens).
  2. Vervolgens gaat de inhoud verder op dezelfde regel als het begin van het aanhalingsteken. Deze inhoud op dezelfde regel kan leeg of niet leeg zijn. 'leeg' staat voor 'volledig witruimte'.
  3. Als de inhoud op dezelfde regel niet leeg is, kan er geen verdere inhoud volgen. Met andere woorden: de literal moet eindigen met hetzelfde aantal aanhalingstekens op dezelfde regel.
  4. Als de inhoud op dezelfde regel leeg is, kan het letterlijke teken doorgaan met een new_line en een aantal volgende inhoudslijnen en new_line's.
    • Een inhoudsregel is tekst behalve een new_line.
    • Het eindigt vervolgens met een new_line, een getal (mogelijk nul) van whitespace en hetzelfde aantal aanhalingstekens waarmee de letterlijke tekst is begonnen.

Onbewerkte letterlijke tekenreekswaarde

De delen tussen de begin- en eind-raw_string_literal_delimiter worden gebruikt om de waarde van de raw_string_literal op de volgende manier te vormen:

  • In het geval van single_line_raw_string_literal zal de waarde van het letterlijke exact de inhoud zijn tussen het begin en het einde van raw_string_literal_delimiter.
  • In het geval van multi_line_raw_string_literal maken de eerste whitespace* new_line en de uiteindelijke new_line whitespace* geen deel uit van de waarde van de tekenreeks. Het laatste whitespace*-gedeelte voorafgaand aan de raw_string_literal_delimiter-terminal wordt echter beschouwd als de 'inspringingsspatie' en zal invloed hebben op hoe de andere regels worden geïnterpreteerd.
  • Als u de uiteindelijke waarde wilt ophalen, wordt de volgorde van (raw_content | new_line)* doorlopen en wordt het volgende uitgevoerd:
    • Als het een new_line de inhoud van de new_line wordt toegevoegd aan de uiteindelijke tekenreekswaarde.
    • Als het geen 'lege' raw_content is (bijvoorbeeld not_new_line+ een niet-whitespace teken bevat):
      • de 'inspring-witruimte' moeten een voorvoegsel van de raw_contentzijn. Het is anders een fout.
      • de 'inspringingsspaties' worden vanaf het begin van raw_content verwijderd en het resterende gedeelte wordt toegevoegd aan de uiteindelijke tekenreekswaarde.
    • Als het een 'leeg' raw_content is (bijvoorbeeld not_new_line+ volledig is whitespace):
      • De 'inspringingsspatie' moet een voorvoegsel zijn van de raw_content of de raw_content moet een voorvoegsel zijn van de 'inspringingsspatie'. Het is anders een fout.
      • aangezien veel van de 'inspringingsspaties' vanaf het begin van raw_content wordt verwijderd en de rest wordt toegevoegd aan de uiteindelijke tekenreekswaarde.

Verduidelijkingen:

  1. Een single_line_raw_string_literal kan een tekenreeks met een new_line waarde er niet in weergeven. Een single_line_raw_string_literal doet niet mee aan het bijsnijden van de inspringingsspaties. De waarde is altijd de exacte tekens tussen de begin- en eindscheidingstekens.

  2. Omdat een multi_line_raw_string_literal de laatste new_line van de laatste inhoudsregel negeert, vertegenwoordigt het volgende een tekenreeks zonder beginnende new_line en geen afsluit-new_line

var v1 = """
         This is the entire content of the string.
         """;

Dit onderhoudt symmetrie met de manier waarop het begin new_line wordt genegeerd en biedt ook een uniforme manier om ervoor te zorgen dat de 'inspringingsspaties' altijd kunnen worden aangepast. Als u een tekenreeks wilt weergeven met een terminal new_line moet er als volgt een extra regel worden opgegeven:

var v1 = """
         This string ends with a new line.

         """;
  1. Een single_line_raw_string_literal kan geen tekenreekswaarde vertegenwoordigen die begint of eindigt met een aanhalingsteken (") hoewel een uitbreiding op dit voorstel wordt gegeven in de sectie Drawbacks waarin wordt aangegeven hoe dit kan worden ondersteund.

  2. Een multi_line_raw_string_literal begint met whitespace* new_line na de eerste raw_string_literal_delimiter. Deze inhoud na het scheidingsteken wordt volledig genegeerd en wordt op geen enkele manier gebruikt bij het bepalen van de waarde van de tekenreeks. Hierdoor kan een mechanisme een raw_string_literal opgeven waarvan de inhoud begint met een " teken zelf. Bijvoorbeeld:

var v1 = """
         "The content of this string starts with a quote
         """;
  1. Een raw_string_literal kan ook inhoud voorstellen die eindigt met een aanhalingsteken ("). Dit wordt ondersteund omdat het afsluitende scheidingsteken op een eigen regel moet staan. Bijvoorbeeld:
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""
         """;
  1. De eis dat een 'lege' raw_content óf een voorvoegsel van de 'inspringingsspaties' moet zijn óf dat de 'inspringingsspaties' een voorvoegsel van de 'lege' raw_content moeten zijn, helpt ervoor te zorgen dat er geen verwarrende scenario's met gemengde witruimte ontstaan, vooral omdat het onduidelijk zou zijn wat er met die regel zou moeten gebeuren. Het volgende geval is bijvoorbeeld ongeldig:
var v1 = """
         Start
<tab>
         End
         """;
  1. Hier is de spatieruimte negen spatietekens, maar de 'lege' raw_content begint niet met een voorvoegsel. Er is geen duidelijk antwoord op hoe die <tab> lijn helemaal moet worden behandeld. Moet het worden genegeerd? Moet het hetzelfde zijn als .........<tab>? Daarom lijkt het het duidelijkst om het illegaal te maken om verwarring te voorkomen.

  2. De volgende gevallen zijn echter legaal en vertegenwoordigen dezelfde tekenreeks:

var v1 = """
         Start
<four spaces>
         End
         """;
var v1 = """
         Start
<nine spaces>
         End
         """;

In beide gevallen zijn de 'inspringingsspaties' negen spaties. En in beide gevallen verwijderen we zoveel mogelijk van dat voorvoegsel, zodat de 'lege' raw_content in elk geval leeg is (zonder rekening te houden met elke new_line). Hierdoor hoeven gebruikers geen witruimte op deze regels te zien, laat staan zich er zorgen over maken, wanneer ze deze regels kopiëren, plakken of bewerken.

  1. In dit specifieke geval van:
var v1 = """
         Start
<ten spaces>
         End
         """;

De inspringingsspaties zijn nog steeds negen spaties. We verwijderen hier echter maximaal de 'inspringingsspaties', en de 'lege' raw_content draagt bij aan één spatie in de uiteindelijke inhoud. Dit maakt het mogelijk voor gevallen waarin de inhoud witruimte nodig heeft op deze regels die moeten worden bewaard.

  1. Het volgende is technisch niet juridisch:
var v1 = """
         """;

Dit komt doordat het begin van de onbewerkte tekenreeks een new_line moet hebben (wat wel het geval is), maar het einde ook een new_line moet hebben (wat niet het geval is). De minimale juridische raw_string_literal is:

var v1 = """

         """;

Deze tekenreeks is echter uitermate oninteressant, omdat deze gelijk is aan "".

Voorbeelden van inspringing

Het algoritme 'inspringwitruimte' kan op verschillende invoer worden gevisualiseerd. In de volgende voorbeelden wordt het verticale staafteken | gebruikt om de eerste kolom in de resulterende onbewerkte tekenreeks te illustreren:

Voorbeeld 1- Standaardcase

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
          """;

wordt geïnterpreteerd als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |</element>
           """;

Voorbeeld 2: Scheidingsteken beëindigen op dezelfde regel als inhoud.

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>""";

Dit is illegaal. De laatste inhoudsregel moet eindigen op een new_line.

Voorbeeld 3: Eindscheidingsteken vóór het beginscheidingsteken

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
""";

wordt geïnterpreteerd als

var xml = """
|          <element attr="content">
|            <body>
|            </body>
|          </element>
""";

Voorbeeld 4: Scheidingsteken beëindigen na beginscheidingsteken

var xml = """
          <element attr="content">
            <body>
            </body>
          </element>
              """;

Dit is illegaal. De regels met inhoud moeten beginnen met de 'inspringingsspaties'

Voorbeeld 5: lege regel leegmaken

var xml = """
          <element attr="content">
            <body>
            </body>

          </element>
          """;

wordt geïnterpreteerd als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

Voorbeeld 6: Lege regel met minder witruimte dan voorvoegsel (puntjes vertegenwoordigen spaties)

var xml = """
          <element attr="content">
            <body>
            </body>
....
          </element>
          """;

wordt geïnterpreteerd als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |
          |</element>
           """;

Voorbeeld 7: lege regel met meer witruimte dan voorvoegsel (puntjes vertegenwoordigen spaties)

var xml = """
          <element attr="content">
            <body>
            </body>
..............
          </element>
          """;

wordt geïnterpreteerd als

var xml = """
          |<element attr="content">
          |  <body>
          |  </body>
          |....
          |</element>
           """;

Gedetailleerd ontwerp (interpolatiegeval)

Interpolaties in normale geïnterpoleerde tekenreeksen (bijvoorbeeld $"...") worden vandaag ondersteund door het gebruik van het { teken om een interpolation te starten en het gebruik van een {{ escape-reeks om een echt open accolade in te voegen. Het gebruik van hetzelfde mechanisme zou doelen '1' en '2' van dit voorstel schenden. Talen die { als een belangrijk teken in hun kern hebben (zoals JavaScript, JSON, Regex en zelfs ingesloten C#) moeten nu escape-tekens gebruiken, waardoor het doel van onbewerkte letterlijke tekenreeksen tenietgedaan wordt.

Ter ondersteuning van interpolaties introduceren we ze op een andere manier dan normaal $" geïnterpoleerde tekenreeksen. Een interpolated_raw_string_literal begint met een aantal $ tekens. Het aantal van deze tekens geeft aan hoeveel { (en }) tekens nodig zijn in de inhoud van de literal om de interpolationaf te bakenen. Het is belangrijk dat er nog steeds geen ontsnappingsmechanisme is voor accolades. Net zoals bij aanhalingstekens (") kan de letterlijke eigenschap altijd ervoor zorgen dat scheidingstekens worden opgegeven voor de interpolaties die gegarandeerd niet botsen met de rest van de inhoud van de tekenreeks. Een letterlijke JSON-code met interpolatiegaten kan bijvoorbeeld als volgt worden geschreven:

var v1 = $$"""
         {
            "orders": 
            [
                { "number": {{order_number}} }
            ]
         }
         """

Hier komt de {{...}} overeen met het vereiste aantal van twee accolades dat door het scheidingstekenvoorvoegsel $$ is gespecificeerd. In het geval van een enkele $ betekent dit dat de interpolatie op dezelfde manier wordt gespecificeerd als {...}, zoals in normale letterlijke tekenreeksen met interpolatie. Belangrijk is dat een geïnterpoleerde letterlijke string met N$ tekens een reeks 2*N-1 accolades (van hetzelfde type achter elkaar) kan hebben. De laatste N accolades beginnen (of beëindigen) een interpolatie en de resterende N-1 accolades zijn alleen inhoud. Bijvoorbeeld:

var v1 = $$"""X{{{1+1}}}Z""";

In dit geval behoren de binnenste twee {{ en }} accolades tot de interpolatie en zijn de buitenste enkelvoudige accolades alleen inhoud. De bovenstaande tekenreeks is dus gelijk aan de inhoud X{2}Z. Gebruik van 2*N accolades (of meer) is altijd incorrect. Om langere reeksen accolades als inhoud te hebben, moet het aantal $ karakters dienovereenkomstig worden verhoogd.

Geïnterpoleerde onbewerkte letterlijke strings zijn gedefinieerd als:

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

Het bovenstaande is vergelijkbaar met de definitie van raw_string_literal, maar met enkele belangrijke verschillen. Een interpolated_raw_string_literal moet worden geïnterpreteerd als:

  1. Het begint met ten minste één dollarteken (maar geen bovengrens) en vervolgens drie aanhalingstekens (ook zonder bovengrens).
  2. Vervolgens gaat de inhoud op dezelfde regel verder als waar de aanhalingstekens beginnen. Deze inhoud op dezelfde regel kan leeg of niet leeg zijn. 'leeg' staat voor 'volledig witruimte'.
  3. Als de inhoud op dezelfde regel niet leeg is, mag er geen verdere inhoud volgen. Met andere woorden: de literal moet eindigen met hetzelfde aantal aanhalingstekens op dezelfde regel.
  4. Als de inhoud op dezelfde regel leeg is, kan het letterlijke teken doorgaan met een new_line en een aantal volgende inhoudslijnen en new_line's.
    • Een inhoudsregel is tekst behalve een new_line.
    • Een regel met inhoud kan meerdere raw_interpolation voorvallen op elke positie bevatten. De raw_interpolation moet beginnen met een gelijk aantal open accolades ({) als het aantal dollartekens aan het begin van de letterlijke tekst.
    • Als 'inspringingsspaties' niet leeg is, kan een raw_interpolation niet onmiddellijk een new_linevolgen.
    • De raw_interpolation volgt de normale regels die zijn opgegeven in §12.8.3. Elke raw_interpolation moet eindigen met hetzelfde aantal sluitaccolades (}) als het aantal dollartekens en openingsaccolades.
    • Elke interpolation kan op dezelfde manier nieuwe regels bevatten als een interpolation in een normale verbatim_string_literal (@"").
    • Het eindigt vervolgens met een new_line, een getal (mogelijk nul) van whitespace en hetzelfde aantal aanhalingstekens waarmee de letterlijke tekst is begonnen.

De berekening van de geïnterpoleerde tekenreekswaarde volgt dezelfde regels als een normale raw_string_literal behalve bijgewerkt om regels met raw_interpolations te verwerken. Het bouwen van de tekenreekswaarde gebeurt op dezelfde manier, waarbij de interpolatiegaten worden vervangen door de waarden die de expressies tijdens uitvoering voortbrengen. Als de interpolated_raw_string_literal wordt geconverteerd naar een FormattableString worden de waarden van de interpolaties in hun respectieve volgorde doorgegeven aan de arguments matrix naar FormattableString.Create. De rest van de inhoud van de interpolated_raw_string_literalnadat de inspringingsspaties is verwijderd van alle regels, wordt gebruikt om de format tekenreeks te genereren die is doorgegeven aan FormattableString.Create, behalve met de juiste genummerde {N} inhoud op elke locatie waar een raw_interpolation heeft plaatsgevonden (of {N,constant} in het geval dat de interpolation van het formulier is expression ',' constant_expression).

Er is een dubbelzinnigheid in de bovenstaande specificatie. Specifiek wanneer een sectie van { in de tekst grenst aan { van een interpolatie. Bijvoorbeeld:

var v1 = $$"""
         {{{order_number}}}
         """

Dit kan worden geïnterpreteerd als: {{ {order_number } }} of { {{order_number}} }. Omdat de voormalige expressie echter illegaal is (geen C#-expressie kan beginnen met {) zou het zinloos zijn om die manier te interpreteren. Dus interpreteren we op de laatste manier, waarbij de binnenste { en } accolades de interpolatie vormen, en eventuele buitenste vormen de tekst. In de toekomst kan dit een probleem zijn als de taal ooit uitdrukkingen ondersteunt die tussen accolades staan. In dat geval zou de aanbeveling echter zijn om een dergelijk geval als volgt te schrijven: {{({some_new_expression_form})}}. Haakjes helpen hier om het expressiegedeelte te onderscheiden van de rest van de letterlijke tekst of interpolatie. Dit heeft al voorrang op de wijze waarop ternaire voorwaardelijke expressies moeten worden verpakt om niet te conflicteren met de opmaak-/uitlijningsaanduiding van een interpolatie (bijvoorbeeld {(x ? y : z)}).

Nadelen

Onbewerkte letterlijke tekenreeksen voegen meer complexiteit toe aan de taal. We hebben al veel letterlijke tekenreeksvormen voor talloze doeleinden. "" tekenreeksen, @"" tekenreeksen en $"" tekenreeksen hebben al veel kracht en flexibiliteit. Maar ze hebben allemaal geen manier om onbewerkte inhoud te bieden die nooit ontsnappen nodig heeft.

De bovenstaande regels bieden geen ondersteuning voor het geval van 4.a:

  1. ...
    • Optioneel, met extra complexiteit, zouden we dit kunnen verfijnen om aan te geven dat: Voor alle tekenreeksen die zelf geen new_line bevatten (maar wel kunnen beginnen of eindigen met een aanhalingsteken "), het mogelijk moet zijn om de letterlijke tekenreeks op één regel te zetten.

Dat komt doordat we geen middelen hebben om te weten dat een begin- of eindcitaat (") tot de inhoud moet behoren en niet tot het scheidingsteken zelf. Als dit echter een belangrijk scenario is dat we willen ondersteunen, kunnen we een parallelle ''' constructie toevoegen om samen met het """ formulier te gaan. Met deze parallelle constructie kan één regeltekenreeks die begint en eindigt met " eenvoudig worden geschreven als '''"This string starts and ends with quotes"''' samen met de parallelle constructie """'This string starts and ends with apostrophes'""". Dit kan ook wenselijk zijn om ondersteuning te bieden bij het visueel scheiden van aanhalingstekens, wat kan helpen bij het insluiten van talen die voornamelijk veel meer dan één aanhalingsteken gebruiken.

Alternatieven

https://github.com/dotnet/csharplang/discussions/89 behandelt hier veel opties. Alternatieven zijn talrijk, maar het lijkt erop dat ze te ver afdwalen naar complexiteit en slechte ergonomie. Deze benadering kiest voor eenvoud, waarbij je simpelweg de lengte van het begin- en eindcitaat blijft vergroten totdat er geen zorgen meer zijn over een conflict met de stringinhoud. Hiermee kunt u ook de code die u schrijft, er goed ingesprongen uitzien, terwijl er nog steeds een gededenteerde letterlijke tekst wordt geproduceerd die de meeste code wil.

Een van de meest interessante mogelijke variaties is echter het gebruik van ` (of ```) afscheidingen voor deze ruwe tekenreeksen. Dit zou verschillende voordelen hebben:

  1. Hiermee voorkomt u alle problemen met tekenreeksen die beginnen of eindigen met aanhalingstekens.
  2. Het zou lijken op Markdown. Hoewel dat op zichzelf mogelijk niet goed is, kunnen gebruikers markdown-interpretatie verwachten.
  3. Een letterlijke rauwe tekenreeks hoeft in de meeste gevallen slechts met één teken te beginnen en eindigen, en hoeft slechts meerdere tekens te bevatten in het veel zeldzamere geval van inhoud die zelf ook back-ticks bevat.
  4. Het zou natuurlijk zijn om dit in de toekomst uit te breiden met ```xml, opnieuw vergelijkbaar met Markdown. Dat geldt natuurlijk ook voor de """ vorm.

Over het algemeen lijkt het nettovoordeel hier echter klein. In overeenstemming met de C#-geschiedenis, denk ik dat " het string literal scheidingsteken moet blijven, net zoals het is voor @"" en $"".

Ontwerpvergaderingen

Openstaande problemen om te bespreken Opgeloste problemen:

  • [x] moeten we een enkele regelvorm hebben? We kunnen het technisch zonder. Maar het zou betekenen dat eenvoudige tekenreeksen die geen nieuwe regel bevatten, altijd ten minste drie regels duren. Ik denk dat we het erg zwaar moeten doen om constructies van één lijn te forceren om drie lijnen te zijn om ontsnappen te voorkomen.

Ontwerpbeslissing: Ja, we zullen een enkelregelige formulier hebben.

  • [x] moeten we vereisen dat met meerdere regels moet beginnen beginnen met een nieuwe regel? Ik denk dat we dat moeten doen. Het biedt ons ook de mogelijkheid om zaken zoals """xml in de toekomst te ondersteunen.

Ontwerpbeslissing: Ja, we vereisen dat meerdere regels moeten beginnen met een nieuwe regel

  • [x] moet de automatische dedenting helemaal worden uitgevoerd? Ik denk dat we dat moeten doen. Code ziet er zo veel aangenamer uit.

Ontwerpbeslissing: Ja, automatisch dedenting wordt uitgevoerd.

  • [x] Moeten we common-whitespace beperken voor het combineren van witruimtetypen? Ik denk niet dat we het moeten doen. Er is inderdaad een algemene inspringingsstrategie genaamd 'tab voor inspringing, spatie voor uitlijning'. Het zou heel natuurlijk zijn om dit te gebruiken om het eindscheidingsteken uit te lijnen met het beginscheidingsteken in een geval waarin het beginscheidingsteken niet begint op een tabstop.

Ontwerpbeslissing: We hebben geen beperkingen voor het mengen van witruimte.

  • [x] Moeten we iets anders gebruiken voor de hekken? ` zou overeenkomen met de markdown-syntaxis en betekent dat we deze tekenreeksen niet altijd hoeven te starten met drie aanhalingstekens. Slechts één zou volstaan voor het gangbare geval.

Ontwerpbeslissing: We gebruiken """

  • [x] Moeten we een vereiste hebben dat het scheidingsteken meer aanhalingstekens bevat dan de langste reeks aanhalingstekens in de tekenreekswaarde? Technisch gezien is het niet vereist. bijvoorbeeld:
var v = """
        contents"""""
        """

Dit is een tekenreeks met """ als scheidingsteken. Verschillende communityleden hebben verklaard dat dit verwarrend is en we moeten in een dergelijke situatie vereisen dat het scheidingsteken altijd meer tekens heeft. Dat zou dan het volgende zijn:

var v = """"""
        contents"""""
        """"""

Ontwerpbeslissing: Ja, het scheidingsteken moet langer zijn dan elke reeks aanhalingstekens die in de tekenreeks zelf voorkomt.