Stringa multilinea letterale in C #


1046

C'è un modo semplice per creare una stringa multilinea letterale in C #?

Ecco quello che ho ora:

string query = "SELECT foo, bar"
+ " FROM table"
+ " WHERE id = 42";

So che ha PHP

<<<BLOCK

BLOCK;

C # ha qualcosa di simile?


1
Non ci sono interruzioni di riga nel tuo esempio. Li vuoi?
weiqure,

8
No. Volevo solo più righe per motivi di visibilità / pulizia del codice.
Chet

6
In tal caso, le stringhe testuali contengono le interruzioni di riga. Puoi usare @ "...". Sostituisci (Environment.NewLine, "") se vuoi.
weiqure,

9
Dovresti considerare di associare il 42parametro come, soprattutto se proviene dall'input dell'utente, per evitare l'iniezione SQL.
Jens Mühlenhoff,

@ JensMühlenhoff come verrà iniettata una stringa codificata, definita nel codice?
Mr. Boy,

Risposte:


1590

Puoi usare il @simbolo davanti a a stringper formare una stringa letterale letterale :

string query = @"SELECT foo, bar
FROM table
WHERE id = 42";

Inoltre , non è necessario sfuggire a caratteri speciali quando si utilizza questo metodo, ad eccezione delle doppie virgolette, come mostrato nella risposta di Jon Skeet.


43
Si tratta di una comunque letterale di stringa - è una parola per parola letterale di stringa con il simbolo @.
Jon Skeet,

95
se la tua stringa contiene virgolette ("), puoi sfuggirle in questo modo:" "(ecco due caratteri tra virgolette)
Muad'Dib

8
C'è un modo di fare quanto sopra senza che crei nuove linee? Ho un testo davvero lungo che mi piacerebbe vedere racchiuso nell'IDE senza dover usare il plus ("ciao" + "lì").
Noelicus,

2
@noelicus - non proprio, ma potresti aggirare il problema usando la tecnica di weiqure sopra di:@"my string".Replace(Environment.NewLine, "")
John Rasch,

8
@afsharm Puoi usare $ @ "text"
Patrick McDonald,

566

Si chiama letteralmente una stringa letterale in C #, ed è solo una questione di mettere @ prima del letterale. Questo non solo consente più linee, ma disattiva anche la fuga. Quindi ad esempio puoi fare:

string query = @"SELECT foo, bar
FROM table
WHERE name = 'a\b'";

Ciò include le interruzioni di riga (utilizzando qualsiasi interruzione di riga utilizzata dal sorgente) nella stringa, tuttavia. Per SQL, questo non è solo innocuo, ma probabilmente migliora la leggibilità ovunque tu veda la stringa, ma in altri luoghi potrebbe non essere necessario, nel qual caso dovresti non utilizzare una stringa letterale multilinea per iniziare, o rimuoverli dalla stringa risultante.

L'unico bit di escape è che se si desidera una virgoletta doppia, è necessario aggiungere un ulteriore simbolo di virgoletta doppia:

string quote = @"Jon said, ""This will work,"" - and it did!";

2
Questa risposta è errata; introduce nuove linee che OP non desidera.
TamaMcGlinn,

@TamaMcGlinn: aggiungerò qualcosa nella risposta al riguardo - non era chiaro quando l'OP ha scritto la domanda.
Jon Skeet,

105

Il problema con l'uso della stringa letterale che trovo è che può rendere il tuo codice un po '" strano " perché per non ottenere spazi nella stringa stessa, deve essere completamente allineato a sinistra:

    var someString = @"The
quick
brown
fox...";

Che schifo.

Quindi la soluzione che mi piace usare, che mantiene tutto ben allineato con il resto del codice è:

var someString = String.Join(
    Environment.NewLine,
    "The",
    "quick",
    "brown",
    "fox...");

E, naturalmente, se si desidera solo per dividere logicamente le linee di un'istruzione SQL, come sei e in realtà non c'è bisogno di una nuova linea, si può sempre e solo sostituire Environment.NewLineper " ".


2
Molto più pulito, grazie. Inoltre, String.Concat funziona in modo simile e non richiede un separatore.
Seth,

Grazie. Mi piace String.Join con il delimitatore "" per SQL poiché consente l'indentazione / corrispondenza del paren ed evita di dover aggiungere lo spazio iniziale.
Rob a TVSeries.com

7
Mentre brutta, la prima versione non richiede alcun codice per l'esecuzione . La seconda opzione ha ovviamente un sovraccarico di runtime per concatenare le stringhe separate.
Codice finito il

@GoneCoding, ne sei sicuro? Il compilatore può ottimizzare la concatenazione.
William Jockusch,

@WilliamJockusch: generalmente le chiamate di funzione non operatore (come join) vengono lasciate intatte e non ottimizzate. Meglio controllare il codice compilato, ma vorrei mettere soldi che la chiamata non è ottimizzata.
Codice finito

104

Un altro aspetto da tenere d'occhio è l'uso dei letterali stringa in string.Format. In tal caso è necessario sfuggire alle parentesi graffe / parentesi graffe "{" e "}".

// this would give a format exception
string.Format(@"<script> function test(x) 
      { return x * {0} } </script>", aMagicValue)
// this contrived example would work
string.Format(@"<script> function test(x) 
      {{ return x * {0} }} </script>", aMagicValue)

14
E che differenza fa? Con o senza "@" devi raddoppiare "{{" per ottenere "{" come carattere stampabile, è questione di String.Format, non di contenuti di stringa.
Greenoldman,

12
È un gotcha notevole per le persone che vogliono inserire il codice Javascript in una stringa, che può essere fatto più spesso in letterali letterali testuali che in stringhe normali.
Ed Brannin,

2
Nel nuovo C # 6.0, è possibile utilizzare un operatore di proprietà indicizzato insieme alla stringa letterale letterale (come $ @ "Il valore è {this.Value}";)
Heliac

2
@Heliac Penso che intendi che le stringhe interpolate possono anche essere letterali con quella sintassi. var query = $ @ "seleziona foo, barra dalla tabella dove id = {id}";
brianary

102

Come nota a margine, con C # 6.0 ora puoi combinare stringhe interpolate con la stringa letterale letterale:

string camlCondition = $@"
<Where>
    <Contains>
        <FieldRef Name='Resource'/>
        <Value Type='Text'>{(string)parameter}</Value>
    </Contains>
</Where>";

10
Bene, non lo sapevo fino ad ora. Se qualcuno è interessato: The $ thingy si chiama "Interpolated Strings" e puoi leggerlo in dettaglio qui: msdn.microsoft.com/en-us/library/dn961160.aspx
Hauke ​​P.

tx, riparato il testo
Heliac,

1
Suppongo che una parentesi graffa riccia letterale debba essere raddoppiata, ad esempio $@"{{example literal text { fooString }. }}" Questo potrebbe confondere alcuni perché Angular, React e Vue.js usano la convenzione opposta.
Patrick Szalapski

58

Perché le persone continuano a confondere le stringhe con i letterali delle stringhe? La risposta accettata è un'ottima risposta a una domanda diversa; non a questo.

So che questo è un vecchio argomento, ma sono venuto qui con forse la stessa domanda del PO, ed è frustrante vedere come le persone continuano a fraintenderlo. O forse sto leggendo male, non lo so.

In parole povere, una stringa è una regione di memoria del computer che, durante l'esecuzione di un programma, contiene una sequenza di byte che possono essere associati a caratteri di testo. Una stringa letterale, d'altra parte, è un pezzo di codice sorgente, non ancora compilato, che rappresenta il valore utilizzato per inizializzare una stringa in seguito, durante l'esecuzione del programma in cui appare.

In C #, la dichiarazione ...

 string query = "SELECT foo, bar"
 + " FROM table"
 + " WHERE id = 42";

... non produce una stringa di tre righe ma una riga; la concatenazione di tre stringhe (ciascuna inizializzata da un letterale diverso) nessuna delle quali contiene un modificatore di nuova riga.

Ciò che l'OP sembra chiedere - almeno quello che vorrei chiedere con quelle parole - non è come introdurre, nella stringa compilata, le interruzioni di riga che imitano quelle trovate nel codice sorgente, ma come spezzare per chiarezza a lungo , singola riga di testo nel codice sorgente senza introdurre interruzioni nella stringa compilata. E senza richiedere un tempo di esecuzione prolungato, impiegato per unire le molteplici sottostringhe provenienti dal codice sorgente. Come le barre rovesciate finali all'interno di una stringa multilinea letterale in javascript o C ++.

Suggerire l'uso di stringhe testuali, nevermind StringBuilders, String.Joinse addirittura funzioni annidate con inversioni di stringa e quant'altro, mi fa pensare che le persone non stiano davvero capendo la domanda. O forse non lo capisco.

Per quanto ne so, C # non (almeno nella versione paleolitica che sto ancora utilizzando, rispetto al decennio precedente) ha una funzione per produrre in modo chiaro valori letterali su più righe che possono essere risolti durante la compilazione piuttosto che nell'esecuzione.

Forse le versioni attuali lo supportano, ma ho pensato di condividere la differenza che percepisco tra stringhe e letterali di stringa.

AGGIORNARE:

(Dal commento di MeowCat2012) Puoi farlo. L'approccio "+" di OP è il migliore. Secondo le specifiche, l'ottimizzazione è garantita: http://stackoverflow.com/a/288802/9399618


1
La confusione che alcuni (incluso me stesso) potrebbero aver avuto guardando la domanda originale è che il formato here-doc (shell, php, perl, ...) include le nuove righe. Quindi, se il PO si confronta con l'eredità di PHP, includere le nuove linee non avrebbe dovuto essere un problema.
Tanktalus,

Esattamente. Per quanto ne so, la tua risposta "no, non puoi farlo in C #" è corretta.
TamaMcGlinn,

Mi è stato detto che in Java, una stringa così concatenata diventerà una singola stringa letterale nel bytecode compilato. Forse anche Dot Net lo fa?
Meow Cat 2012,

2
Puoi. L'approccio "+" di OP è il migliore. Secondo le specifiche, l'ottimizzazione è garantita: stackoverflow.com/a/288802/9399618 Sei ancora uno dei pochi a capire la domanda. Sarebbe possibile rimuovere o piegare risposte potenzialmente fuorvianti ma accettate?
Meow Cat 2012,

1
Grazie per il suggerimento, @ MeowCat2012. Guardando un po 'di codice decompilato, sembra proprio che sia così.
Carvo Loco,

12

Non l'ho visto, quindi lo posterò qui (se sei interessato a passare una stringa puoi farlo anche tu.) L'idea è che puoi spezzare la stringa su più righe e aggiungere il tuo contenuto (anche su più righe) nel modo desiderato. Qui "tableName" può essere passato nella stringa.

    private string createTableQuery = "";

    void createTable(string tableName)
    {

         createTableQuery = @"CREATE TABLE IF NOT EXISTS
                ["+ tableName  + @"] (
               [ID] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
               [Key] NVARCHAR(2048)  NULL, 
               [Value] VARCHAR(2048)  NULL
                                )";
    }

10
piuttosto pericoloso direi: facile per qualcuno fare iniezioni di sql in quel modo.
Kai,

4
Va bene purché tu sappia che tutte le tue variabili (se presenti!) Nella stringa di query provengono da costanti di codice o da un'altra fonte sicura - ad esempio, createTable("MyTable"); in ogni caso, la domanda dell'OP era su come inserire valori letterali di stringa multilinea direttamente nel codice , non come costruire query di database di per sé. :)
dbeachy1,

2
dovrebbe probabilmente usare un generatore di stringhe, soprattutto se il numero di vantaggi (+) è molto.
Gldraphael,

8

Puoi usare @ e "" .

        string sourse = @"{
        ""items"":[
        {
            ""itemId"":0,
            ""name"":""item0""
        },
        {
            ""itemId"":1,
            ""name"":""item1""
        }
        ]
    }";

2
Dovresti spiegare cosa significa ciascuno, poiché @ sta per stringa testuale e "" serve per evitare virgolette doppie.
AFract

4

Sì, puoi dividere una stringa su più righe senza introdurre nuove righe nella stringa effettiva, ma non è abbastanza:

string s = $@"This string{
string.Empty} contains no newlines{
string.Empty} even though it is spread onto{
string.Empty} multiple lines.";

Il trucco consiste nell'introdurre il codice che viene valutato come vuoto e tale codice può contenere newline senza influire sull'output. Ho adattato questo approccio da questa risposta a una domanda simile.

Apparentemente c'è un po 'di confusione su quale sia la domanda, ma ci sono due suggerimenti che quello che vogliamo qui è una stringa letterale che non contiene caratteri di nuova riga, la cui definizione si estende su più righe. (nei commenti lo dice, ed "ecco quello che ho" mostra il codice che non crea una stringa con al suo interno delle righe)

Questo test unitario mostra l'intento:

    [TestMethod]
    public void StringLiteralDoesNotContainSpaces()
    {
        string query = "hi"
                     + "there";
        Assert.AreEqual("hithere", query);
    }

Modificare la definizione sopra di query in modo che sia un valore letterale di stringa, anziché la concatenazione di due valori letterali di stringa che possono essere o meno ottimizzati in uno dal compilatore.

L'approccio C ++ sarebbe quello di terminare ogni riga con una barra rovesciata, facendo in modo che il carattere newline fosse evitato e non apparisse nell'output. Sfortunatamente, c'è ancora il problema che ogni riga dopo la prima deve essere allineata a sinistra per non aggiungere spazi bianchi al risultato.

Esiste solo un'opzione che non si basa su ottimizzazioni del compilatore che potrebbero non verificarsi, che consiste nel mettere la definizione su una riga. Se vuoi fare affidamento sulle ottimizzazioni del compilatore, il + che hai già è ottimo; non è necessario allineare a sinistra la stringa, non si ottengono nuove righe nel risultato ed è solo un'operazione, nessuna chiamata di funzione, su cui aspettarsi l'ottimizzazione.


1
Creativo. Tuttavia sembra che (non confermato) questo sarebbe trattato come una stringa di formato e potrebbe essere o meno ottimizzato. D'altra parte, l'approccio "+" di OP è il migliore. Secondo le specifiche, l'ottimizzazione è garantita: stackoverflow.com/a/288802/9399618
Meow Cat 2012

4

Aggiungi più righe: usa @

string query = @"SELECT foo, bar
FROM table
WHERE id = 42";

Aggiungi valori stringa al centro: usa $

string text ="beer";
string query = $"SELECT foo {text} bar ";

Stringa di più righe Aggiungi valori al centro: usa $ @

string text ="Customer";
string query = $@"SELECT foo, bar
FROM {text}Table
WHERE id = 42";

3

Se non vuoi spazi / newline, l'aggiunta di stringhe sembra funzionare:

var myString = String.Format(
  "hello " + 
  "world" +
  " i am {0}" +
  " and I like {1}.",
  animalType,
  animalPreferenceType
);
// hello world i am a pony and I like other ponies.

Se lo desideri, puoi eseguire quanto sopra qui .


2
Un difetto (involontariamente dimostrato) con questo approccio è che devi stare molto attento a includere gli spazi dove li desideri. Consiglierei un approccio più coerente di quello che ho adottato (ad esempio, sempre all'inizio della riga).
rastrellare

stringa + stringa è proprio ciò con cui OP ha iniziato, però.
TamaMcGlinn,

1

So di essere un po 'in ritardo alla festa, ma desidero raccomandare https://www.buildmystring.com/ per i futuri lettori di questa discussione. È possibile convertire qualsiasi codice in letterale stringa C # utilizzando questo sito.


-10

Puoi usare questi due metodi:

    private static String ReverseString(String str)
    {
        int word_length = 0;
        String result = "";
        for (int i = 0; i < str.Length; i++)
        {
            if (str[i] == ' ')
            {
                result = " " + result;
                word_length = 0;
            }
            else
            {
                result = result.Insert(word_length, str[i].ToString());
                word_length++;
            }
        }
        return result;
    }
//NASSIM LOUCHANI
    public static string SplitLineToMultiline(string input, int rowLength)
    {
        StringBuilder result = new StringBuilder();
        StringBuilder line = new StringBuilder();

        Stack<string> stack = new Stack<string>(ReverseString(input).Split(' '));

        while (stack.Count > 0)
        {
            var word = stack.Pop();
            if (word.Length > rowLength)
            {
                string head = word.Substring(0, rowLength);
                string tail = word.Substring(rowLength);

                word = head;
                stack.Push(tail);
            }

            if (line.Length + word.Length > rowLength)
            {
                result.AppendLine(line.ToString());
                line.Clear();
            }

            line.Append(word + " ");
        }

        result.Append(line);
        return result.ToString();
    }

In SplitLineToMultiline (), è necessario definire la stringa che si desidera utilizzare e la lunghezza della riga, è molto semplice. Grazie .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.