Condividi tramite


stringa letterale grezza

Nota

Questo articolo è una specifica di funzionalità. La specifica funge da documento di progettazione per la funzionalità. Include le modifiche specifiche proposte, insieme alle informazioni necessarie durante la progettazione e lo sviluppo della funzionalità. Questi articoli vengono pubblicati fino a quando le modifiche specifiche proposte non vengono completate e incorporate nella specifica ECMA corrente.

Potrebbero verificarsi alcune discrepanze tra la specifica di funzionalità e l'implementazione completata. Quelle differenze vengono registrate nelle note pertinenti del language design meeting (LDM) .

Altre informazioni sul processo per l'adozione di speclet di funzionalità nello standard del linguaggio C# sono disponibili nell'articolo sulle specifiche di .

Sommario

Consentire una nuova forma di valore letterale stringa che inizia con un minimo di tre caratteri """ (ma nessun massimo), seguita facoltativamente da un new_line, il contenuto della stringa e quindi termina con lo stesso numero di virgolette con cui il valore letterale è iniziato. Per esempio:

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

Poiché il contenuto annidato potrebbe voler usare """, i delimitatori iniziali/finali possono essere più lunghi, ad esempio:

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

Per semplificare la lettura del testo e consentire il rientro che gli sviluppatori apprezzano nel codice, questi letterali di stringa rimuoveranno naturalmente il rientro specificato nell'ultima riga al momento della produzione del valore letterale finale. Ad esempio, un valore letterale del formato:

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

Conterrà i contenuti:

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

Ciò consente al codice di apparire naturale, pur producendo valori letterali desiderati ed evitando i costi di runtime, se necessario l'uso di routine di manipolazione di stringhe specializzate.

Se il comportamento di rientro non è desiderato, è anche semplice disabilitarlo come segue:

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

È supportato anche un modulo a riga singola. Inizia con un minimo di tre caratteri """ (ma nessun massimo), il contenuto della stringa (che non può contenere caratteri new_line) e termina con lo stesso numero di virgolette con cui il valore letterale è iniziato. Per esempio:

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

Sono supportate anche stringhe non elaborate interpolate. In questo caso, la stringa specifica il numero di parentesi graffe necessarie per avviare un'interpolazione (determinata dal numero di segni di dollaro presenti all'inizio del valore letterale). Qualsiasi sequenza di parentesi graffe con meno parentesi graffe viene semplicemente trattata come contenuto. Per esempio:

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

Motivazione

C# non dispone di un modo generale per creare valori letterali stringa semplici che possano contenere effettivamente qualsiasi testo arbitrario. Tutti i formati letterali stringa C# richiedono oggi una qualche forma di escape nel caso in cui il contenuto usi un carattere speciale (sempre se viene usato un delimitatore). In questo modo si evita di avere facilmente valori letterali contenenti altri linguaggi, ad esempio un valore letterale XML, HTML o JSON.

Tutti gli approcci correnti per formare questi valori letterali in C# oggi forzano sempre l'utente a eseguire manualmente l'escape del contenuto. La modifica a quel punto può essere molto fastidiosa perché l'escape non può essere evitato e deve essere gestito ogni volta che si verifica nei contenuti. Questo è particolarmente doloroso per le regex, soprattutto quando contengono virgolette o barre rovesciate. Anche con una stringa verbatim (@""), le virgolette devono essere precedute da caratteri di escape, il che porta a un mix di codice C# e espressioni regolari (regex) intercalati. { e } sono analogamente frustranti nelle stringhe interpolate ($"").

Il punto cruciale del problema è che tutte le stringhe hanno un delimitatore di inizio/fine fisso. Purché questo sia il caso, sarà sempre necessario disporre di un meccanismo di escape perché il contenuto della stringa potrebbe dover specificare il delimitatore finale nel contenuto. Ciò è particolarmente problematico perché il delimitatore " è estremamente comune in molti linguaggi.

Per risolvere questo problema, questa proposta consente delimitatori di inizio e fine flessibili in modo che possano sempre essere fatti in modo che non siano in conflitto con il contenuto della stringa.

Obiettivi

  1. Fornire un meccanismo che consentirà tutti i valori stringa di forniti dall'utente senza la necessità di qualsiasi sequenza di escape. Poiché tutte le stringhe devono essere rappresentabili senza sequenze di escape, è sempre possibile che l'utente specifichi delimitatori che non sia in conflitto con alcun contenuto di testo.
  2. Supportare le interpolazioni nello stesso modo. Come in precedenza, poiché tutte le stringhe devono essere rappresentabili senza caratteri di escape, deve essere sempre possibile per l'utente specificare un delimitatore interpolation che non sia in conflitto con alcun contenuto di testo. È importante che i linguaggi che usano i caratteri delimitatori di interpolazione ({ e }) dovrebbero essere di prima classe e non difficili da usare.
  3. I valori letterali stringa su più righe dovrebbero sembrare piacevoli nel codice e non dovrebbero rendere strano il rientro all'interno dell'unità di compilazione. È importante che i valori letterali senza rientro non vengano costretti a occupare la prima colonna del file, poiché ciò può interrompere il flusso di codice e renderli non allineati con il resto del codice simile che li circonda.
    • Questo comportamento dovrebbe essere facile da sovrascrivere mantenendo le espressioni letterali chiare e facili da leggere.
  4. Per tutte le stringhe che non contengono un new_line o un inizio o una fine con un carattere virgolette ("), dovrebbe essere possibile rappresentare il valore letterale stringa stesso su una singola riga.
    • Facoltativamente, con maggiore complessità, potremmo affinare per dire che: per tutte le stringhe che non contengono un new_line (ma che possono iniziare o terminare con un carattere di virgolette "), dovrebbe essere possibile rappresentare il letterale della stringa stessa su una singola riga. Per altri dettagli, vedere la proposta espansa nella sezione Drawbacks.

Progettazione dettagliata (caso di non interpolazione)

Aggiungeremo una nuova produzione string_literal con il formato seguente:

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

Il delimitatore finale per un raw_string_literal deve corrispondere al delimitatore iniziale. Pertanto, se il delimitatore iniziale è """"" anche il delimitatore finale deve essere tale.

La grammatica precedente per un raw_string_literal deve essere interpretata come:

  1. Inizia con almeno tre virgolette (ma nessun limite superiore sulle virgolette).
  2. Continua quindi con il contenuto sulla stessa riga delle virgolette iniziali. Questi contenuti nella stessa riga possono essere vuoti o non vuoti. 'blank' è sinonimo di 'interamente spazi bianchi'.
  3. Se il contenuto della stessa riga non è vuoto, non è possibile seguire altri contenuti. In altre parole, il literal deve terminare con lo stesso numero di virgolette sulla stessa riga.
  4. Se il contenuto della stessa riga è vuoto, il valore letterale può continuare con un new_line e un certo numero di righe di contenuto successive e new_lines.
    • Una riga di contenuto è qualsiasi testo, ad eccezione di un new_line.
    • Termina quindi con un new_line, seguito da un certo numero (eventualmente zero) di whitespace e dallo stesso numero di virgolette con cui è iniziato il valore letterale.

Valore letterale stringa non elaborato

Le parti tra il raw_string_literal_delimiter iniziale e finale vengono utilizzate per formare il valore del raw_string_literal nel modo seguente:

  • Nel caso di single_line_raw_string_literal il valore letterale sarà esattamente il contenuto tra l'inizio e la fine di raw_string_literal_delimiter.
  • Nel caso di multi_line_raw_string_literal il whitespace* new_line iniziale e il new_line whitespace* finale non fa parte del valore della stringa. Tuttavia, la porzione finale whitespace* precedente al terminale raw_string_literal_delimiter viene considerata lo "spazio di indentazione" e influirà sul modo in cui vengono interpretate le altre righe.
  • Per ottenere il valore finale, si percorre la sequenza di (raw_content | new_line)* e si esegue quanto segue:
    • Se è un new_line il contenuto del new_line viene aggiunto al valore di stringa finale.
    • Se non è un raw_content "vuoto" (cioè not_new_line+ contiene un carattere che non èwhitespace):
      • Lo spazio vuoto di rientro deve essere un prefisso del raw_content. In caso contrario, si tratta di un errore.
      • Gli spazi di indentazione vengono rimossi dall'inizio di raw_content e la parte rimanente viene aggiunta al valore finale della stringa.
    • Se si tratta di un raw_content "vuoto", ad esempio not_new_line+ è interamente whitespace):
      • Il "rientro vuoto" deve essere un prefisso del raw_content o il raw_content deve essere un prefisso del "rientro vuoto". In caso contrario, si tratta di un errore.
      • poiché gran parte degli spazi bianchi di indentazione viene rimossa dall'inizio di raw_content e l'eventuale resto viene aggiunto al valore finale della stringa.

Chiarimenti:

  1. Un single_line_raw_string_literal non è in grado di rappresentare una stringa con un valore new_line. Un single_line_raw_string_literal non partecipa al taglio degli spazi bianchi di rientro. Il suo valore è sempre esattamente i caratteri tra i delimitatori iniziali e finali.

  2. Poiché un multi_line_raw_string_literal ignora il new_line finale dell'ultima riga di contenuto, di seguito rappresenta una stringa senza un new_line iniziale e un new_line finale

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

Ciò mantiene la simmetria con il modo in cui il new_line iniziale viene ignorato e fornisce anche un modo uniforme per garantire che lo spazio vuoto di rientro possa essere sempre regolato. Per rappresentare una stringa con un terminale new_line è necessario specificare una riga aggiuntiva come segue:

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

         """;
  1. Un single_line_raw_string_literal non può rappresentare un valore stringa che inizia o termina con una virgoletta (") anche se viene fornita un'estensione a questa proposta nella sezione Drawbacks che mostra come può essere supportato.

  2. Un multi_line_raw_string_literal inizia con whitespace* new_line dopo il raw_string_literal_delimiteriniziale. Questo contenuto dopo il delimitatore viene completamente ignorato e non viene usato in alcun modo quando si determina il valore della stringa. Ciò consente a un meccanismo di specificare un raw_string_literal il cui contenuto inizia con un carattere " stesso. Per esempio:

var v1 = """
         "The content of this string starts with a quote
         """;
  1. Un raw_string_literal può anche rappresentare il contenuto che termina con una citazione ("). Questa opzione è supportata perché il delimitatore di terminazione deve trovarsi su una riga a sé stante. Per esempio:
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. Il requisito che un "vuoto" raw_content sia un prefisso dello "spazio vuoto di rientro" o che lo "spazio vuoto di rientro" debba essere un prefisso del "vuoto" raw_content aiuta a garantire che non si verifichino scenari confusi con spazi vuoti misti, specialmente perché sarebbe poco chiaro cosa dovrebbe succedere in tale riga. Ad esempio, il caso seguente è illegale:
var v1 = """
         Start
<tab>
         End
         """;
  1. Qui lo "spazio di indentazione" è costituito da nove caratteri di spazio, ma il "vuoto" raw_content non inizia con un prefisso di questi. Non c'è una risposta chiara su come la linea <tab> debba essere trattata. Deve essere ignorato? Dovrebbe essere uguale a .........<tab>? Di conseguenza, renderlo illegale sembra il modo più chiaro per evitare confusione.

  2. I casi seguenti sono validi e rappresentano la stessa stringa:

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

In entrambi questi casi, lo spazio vuoto di rientro sarà di nove spazi. In entrambi i casi, si rimuoverà la massima parte possibile di tale prefisso, in modo che il raw_content risulti vuoto in ogni caso (escludendo ogni new_line). Ciò consente agli utenti di non dover visualizzare e potenzialmente preoccuparsi degli spazi vuoti su queste righe quando copiano/incollano o modificano queste righe.

  1. Nel caso invece di:
var v1 = """
         Start
<ten spaces>
         End
         """;

Lo spazio di indentazione sarà comunque di nove spazi. In questo caso, tuttavia, verrà rimosso tutto il possibile degli spazi vuoti di rientro e il raw_content "vuoto" aggiungerà un singolo spazio al contenuto finale. Ciò consente i casi in cui il contenuto richiede spazi vuoti in queste righe che devono essere mantenuti.

  1. Di seguito sono tecnicamente non legali:
var v1 = """
         """;

Ciò è dovuto al fatto che l'inizio della stringa grezza deve avere un new_line (che c'è), ma la fine deve avere anche un new_line (che non c'è). Il raw_string_literal legale minimo è:

var v1 = """

         """;

Tuttavia, questa stringa è decisamente poco interessante perché equivale a "".

Esempi di rientro

L'algoritmo "spazi bianchi di indentazione" può essere visualizzato su diversi input in questo modo. Negli esempi seguenti viene usato il carattere barra verticale | per illustrare la prima colonna nella stringa non elaborata risultante:

Esempio 1 - Caso standard

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

viene interpretato come

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

Esempio 2: delimitatore finale nella stessa riga del contenuto.

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

Questo è illegale. L'ultima riga di contenuto deve terminare con un new_line.

Esempio 3 - Delimitatore finale prima del delimitatore iniziale

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

viene interpretato come

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

Esempio 4 - Delimitatore finale dopo il delimitatore iniziale

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

Questo è illegale. Le righe di contenuto devono iniziare con lo spazio di indentazione.

Esempio 5 - Riga vuota

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

          </element>
          """;

viene interpretato come

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

Esempio 6 - Riga vuota con meno spazi vuoti rispetto al prefisso (i punti rappresentano spazi)

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

viene interpretato come

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

Esempio 7 - Riga vuota con più spazi vuoti rispetto al prefisso (i punti rappresentano spazi)

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

viene interpretato come

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

Progettazione dettagliata (caso di interpolazione)

Le interpolazioni nelle normali stringhe interpolate (ad esempio, $"...") sono attualmente supportate tramite l'uso del carattere { per avviare un interpolation e l'uso di una sequenza di escape {{ per inserire un carattere di parentesi graffa aperta reale. L'uso di questo stesso meccanismo viola gli obiettivi "1" e "2" della proposta. I linguaggi con { come carattere di base (ad esempio JavaScript, JSON, Regex e persino C#) richiedono ora l'escape, annullando lo scopo dei valori letterali stringa non elaborati.

Per supportare le interpolazioni, le introduciamo in modo diverso rispetto alle normali $" stringhe interpolate. In particolare, un interpolated_raw_string_literal inizierà con un certo numero di caratteri $. Il conteggio di questi indica il numero di caratteri { (e }) necessari nel contenuto del letterale per delimitare il interpolation. Importante, non esiste ancora alcun meccanismo di escape per le parentesi graffe. Piuttosto, proprio come con le virgolette ("), il valore letterale stesso può sempre garantire di specificare delimitatori per le interpolazioni che sono certi di non entrare in conflitto con il resto del contenuto della stringa. Ad esempio, un valore letterale JSON contenente i fori di interpolazione può essere scritto come segue:

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

In questo caso, il {{...}} corrisponde al numero richiesto di due parentesi graffe specificato dal prefisso del delimitatore $$. Nel caso di una singola $, ciò significa che l'interpolazione è specificata proprio come {...} nei normali valori letterali di stringa interpolati. È importante sottolineare che un valore letterale interpolato con N$ caratteri può avere una sequenza di parentesi graffe 2*N-1 (dello stesso tipo in successione). L'ultima parentesi graffa N inizierà (o terminerà) un'interpolazione, mentre le parentesi graffe rimanenti N-1 costituiranno semplicemente il contenuto. Per esempio:

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

In questo caso le parentesi graffe interne {{ e }} appartengono all'interpolazione, mentre le parentesi graffe esterne sono semplicemente contenuto. La stringa precedente è quindi equivalente al contenuto X{2}Z. La presenza di 2*N (o più parentesi graffe) è sempre un errore. Per avere sequenze di parentesi graffe più lunghe come contenuto, il numero di caratteri $ deve essere aumentato di conseguenza.

I valori letterali stringa non elaborati interpolati sono definiti come:

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

Quanto sopra è simile alla definizione di raw_string_literal, ma con alcune differenze importanti. Un interpolated_raw_string_literal deve essere interpretato come:

  1. Inizia con almeno un segno di dollaro (ma senza limite superiore) e poi tre virgolette (anche senza limite superiore).
  2. Continua quindi con il contenuto nella stessa riga delle virgolette iniziali. Questo contenuto nella stessa riga può essere vuoto o non vuoto. 'blank' è sinonimo di 'interamente spazi bianchi'.
  3. Se il contenuto della stessa riga non è vuoto, non è possibile seguire altri contenuti. In altre parole, il literal deve terminare con lo stesso numero di virgolette sulla stessa riga.
  4. Se il contenuto della stessa riga è vuoto, il valore letterale può continuare con un new_line e un certo numero di righe di contenuto successive e new_lines.
    • Una riga di contenuto è qualsiasi testo, ad eccezione di un new_line.
    • Una riga di contenuto può contenere più occorrenze raw_interpolation in qualsiasi posizione. Il raw_interpolation deve iniziare con un numero uguale di parentesi graffe aperte ({) come numero di segni di dollaro all'inizio del valore letterale.
    • Se lo spazio di rientro non è vuoto, un raw_interpolation non può seguire immediatamente un new_line.
    • Il raw_interpolation seguirà le normali regole specificate in §12.8.3. Qualsiasi raw_interpolation deve terminare con lo stesso numero di parentesi graffe di chiusura (}) come segni di dollaro e parentesi graffe aperte.
    • Qualsiasi interpolation può contenere nuove righe all'interno dello stesso modo di un interpolation in un normale verbatim_string_literal (@"").
    • Termina quindi con un new_line, seguito da un certo numero (eventualmente zero) di whitespace e dallo stesso numero di virgolette con cui è iniziato il valore letterale.

Il calcolo del valore della stringa interpolata segue le stesse regole di un normale raw_string_literal ad eccezione dell'aggiornamento per gestire le righe contenenti raw_interpolations. La compilazione del valore stringa avviene nello stesso modo, solo con i fori di interpolazione sostituiti con i valori prodotti da tali espressioni in fase di esecuzione. Se il interpolated_raw_string_literal viene convertito in un FormattableString, i valori delle interpolazioni vengono passati nel rispettivo ordine alla matrice arguments a FormattableString.Create. Il resto del contenuto del interpolated_raw_string_literaldopo 'spazio vuoto di rientro' è stato rimosso da tutte le righe verrà utilizzata per generare la stringa format passata a FormattableString.Create, ad eccezione del contenuto {N} correttamente numerato in ogni posizione in cui si è verificato un raw_interpolation (o {N,constant} nel caso in cui il relativo interpolation sia del formato expression ',' constant_expression).

Esiste un'ambiguità nella specifica precedente. In particolare quando una sezione di { nel testo e { di un'interpolazione si incontrano. Per esempio:

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

Questo può essere interpretato come: {{ {order_number } }} o { {{order_number}} }. Tuttavia, poiché il primo è illegale (nessuna espressione C# potrebbe iniziare con {) sarebbe inutile interpretare questo modo. Quindi interpretiamo in quest'ultima maniera, dove le parentesi graffe più interne { e } formano l'interpolazione e quelle più esterne formano il testo. In futuro potrebbe trattarsi di un problema se il linguaggio dovesse supportare eventuali espressioni racchiuse tra parentesi graffe. Tuttavia, in questo caso, la raccomandazione consiste nel scrivere un caso simile al seguente: {{({some_new_expression_form})}}. In questo caso, le parentesi aiuterebbero a distinguere la parte dell'espressione dal resto della parte letterale/interpolazione. Questo ha già un precedente con il modo in cui le espressioni condizionali ternarie devono essere racchiuse per non entrare in conflitto con lo specificatore di formattazione/allineamento di un'interpolazione (ad esempio, {(x ? y : z)}).

Svantaggi

I valori letterali stringa non elaborati aggiungono maggiore complessità al linguaggio. Sono già disponibili molte forme letterali di stringhe per diversi scopi. "" stringhe, stringhe @"" e stringhe di $"" hanno già molta potenza e flessibilità. Ma a tutti manca un modo per fornire contenuti grezzi che non hanno mai bisogno di essere trasformati.

Le regole precedenti non supportano il caso di 4.a:

  1. ...
    • Facoltativamente, con maggiore complessità, potremmo affinare per dire che: per tutte le stringhe che non contengono un new_line (ma che possono iniziare o terminare con un carattere di virgolette "), dovrebbe essere possibile rappresentare il letterale della stringa stessa su una singola riga.

Non abbiamo modo di sapere se una virgoletta iniziale o finale (") debba appartenere al contenuto e non al delimitatore stesso. Se si tratta di uno scenario importante che si vuole supportare, è possibile aggiungere un costrutto ''' parallelo per accompagnare il modulo """. Con tale costrutto parallelo, una singola stringa di riga che inizia e termina con " può essere scritta facilmente come '''"This string starts and ends with quotes"''' insieme al costrutto parallelo """'This string starts and ends with apostrophes'""". Può anche essere desiderabile sostenere il processo di separazione visiva dei caratteri di virgolette, cosa che può aiutare nell'integrazione di lingue che utilizzano principalmente un carattere di virgolette molto più di un altro.

Alternative

https://github.com/dotnet/csharplang/discussions/89 copre molte opzioni qui. Le alternative sono numerose, ma tendono ad avventurarsi troppo nella complessità e a mostrare scarsa ergonomia. Questo approccio sceglie la semplicità e si limita ad aumentare la lunghezza delle virgolette iniziali/finali finché non si creano conflitti con il contenuto della stringa. Consente anche al codice scritto di apparire correttamente rientrato, pur producendo un valore letterale dedentato che è quello che la maggior parte del codice vuole.

Una delle varianti potenziali più interessanti è tuttavia l'uso di delimitatori ` (o ```) per questi valori letterali di stringhe non elaborate. Questo potrebbe avere diversi vantaggi:

  1. Eviterebbe tutti i problemi relativi alle stringhe che iniziano o finiscono con le virgolette.
  2. Assomiglierebbe a markdown. Anche se questo potenzialmente non è una buona cosa di per sé, poiché gli utenti potrebbero aspettarsi l'interpretazione del markdown.
  3. Un letterale di stringa grezza deve solo iniziare e terminare con un singolo carattere nella maggior parte dei casi e avrebbe bisogno solo di più nel caso, molto più raro, di contenuti che contengono accenti gravi.
  4. Sarebbe naturale estenderlo in futuro con ```xml, simile al markdown. Tuttavia, naturalmente, questo vale anche per la forma """.

Tuttavia, il vantaggio netto qui sembra piccolo. In linea con la cronologia di C#, credo che " debba continuare a essere il delimitatore string literal, proprio come per @"" e $"".

Riunioni di progettazione

Problemi aperti da discutere Problemi risolti:

  • [x] dovremmo avere un modulo a riga singola? Tecnicamente potremmo fare senza di esso. Significherebbe che le stringhe semplici che non contengono una nuova riga richiederebbero sempre almeno tre righe. Penso che sia eccessivamente pesante costringere i costrutti su una sola linea a diventare tre linee solo per evitare l'escaping.

Decisione di progettazione: Sì, avremo un modulo a riga singola.

  • [x] dovremmo richiedere che la multilinea debba iniziare con una nuova riga? Credo che dovremmo. Ci dà anche la possibilità di supportare cose come """xml in futuro.

Decisione di progettazione: Sì, è necessario che la multilinea inizi con una nuova riga

  • [x] il rientro automatico deve essere eseguito del tutto? Credo che dovremmo. Fa sembrare il codice molto più gradevole.

Decisione di progettazione: Sì, verrà eseguito il rientro automatico.

  • [x] dovremmo limitare la combinazione di diversi tipi di spazi bianchi in common-whitespace? Non credo che dovremmo. Esiste infatti una strategia comune di rientro denominata "tabulazione per il rientro, spazio per l'allineamento". Sarebbe molto naturale usarlo per allineare il delimitatore finale al delimitatore iniziale in un caso in cui il delimitatore iniziale non inizia in corrispondenza di una tabulazione.

Decisione di progettazione: non ci saranno restrizioni sulla combinazione di spazi vuoti.

  • [x] dovremmo usare qualcos'altro per le recinzioni? ` corrisponderebbe alla sintassi markdown e non era necessario iniziare sempre queste stringhe con tre virgolette. Solo uno sarebbe sufficiente per il caso comune.

Decisione di progettazione: useremo """

  • [x] dovremmo richiedere che il delimitatore contenga più virgolette rispetto alla sequenza di virgolette più lunga nel valore della stringa? Tecnicamente non è obbligatorio. Per esempio:
var v = """
        contents"""""
        """

Questa è una stringa con """ come delimitatore. Diversi membri della community hanno dichiarato che questo è confuso e dovremmo richiedere in questi casi che il delimitatore abbia sempre più caratteri. Questo sarebbe poi:

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

Decisione di progettazione: Sì, il delimitatore deve essere più lungo di qualsiasi sequenza di virgolette nella stringa stessa.