Sequência de linhas multilinha literal em C #

1046

Existe uma maneira fácil de criar uma literal de seqüência de caracteres multilinha em c #?

Aqui está o que eu tenho agora:

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

Eu sei que o PHP tem

<<<BLOCK

BLOCK;

C # tem algo parecido?

Chet
fonte
1
Não há quebras de linha no seu exemplo. Você quer eles?
288 weiqure
8
Não. Eu só queria várias linhas por motivos de visibilidade / limpeza do código.
Chet
6
Nesse caso, as seqüências textuais contêm as quebras de linha. Você pode usar @ "...". Substitua (Environment.NewLine, "") se desejar.
288 weiqure
9
Você deve considerar vincular o 42parâmetro como, especialmente se for proveniente da entrada do usuário, para evitar a injeção de SQL.
Jens Mühlenhoff 24/10
@ JensMühlenhoff, como alguém injeta uma string codificada, definida no código?
Mr. Boy

Respostas:

1590

Você pode usar o @símbolo na frente de a stringpara formar uma string literal literal :

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

Você também não precisa escapar de caracteres especiais ao usar esse método, exceto aspas duplas, como mostrado na resposta de Jon Skeet.

John Rasch
fonte
43
É uma string literal de qualquer maneira - é uma literal literal com o sinal @.
9139 Jon Skeet
95
Se a seqüência contém aspas ( "), você pode escapar-lhes assim: '' (que é dois caracteres de aspas duplas)
Muad'Dib
8
Existe uma maneira de fazer o que precede sem criar novas linhas? Eu tenho um pedaço de texto muito longo que gostaria de ver envolvido no IDE sem precisar usar o sinal de mais ("oi" + "lá").
Noelicus
2
@noelicus - na verdade não, mas você pode contornar isso usando a técnica de weiqure acima:@"my string".Replace(Environment.NewLine, "")
John Rasch
8
@afsharm Você pode usar $ @ "texto"
Patrick McDonald
566

Ele é chamado literalmente de string literal em C #, e é apenas uma questão de colocar @ antes do literal. Isso não apenas permite várias linhas, mas também desativa o escape. Então, por exemplo, você pode fazer:

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

Isso inclui as quebras de linha (usando qualquer quebra de linha que sua fonte as tenha como) na string, no entanto. Para o SQL, isso não é apenas inofensivo, mas provavelmente melhora a legibilidade em qualquer lugar em que você vê a string - mas em outros lugares pode não ser necessário; nesse caso, você precisará não usar uma literal literal de várias linhas de string para começar, ou remova-os da sequência resultante.

O único meio de escapar é que, se você quiser uma aspas duplas, precisará adicionar um símbolo extra de aspas duplas:

string quote = @"Jon said, ""This will work,"" - and it did!";
Jon Skeet
fonte
2
Esta resposta está incorreta; introduz novas linhas que o OP não deseja.
TamaMcGlinn 23/10/19
@TamaMcGlinn: Vou acrescentar algo à resposta sobre isso - não ficou claro quando o OP escreveu a pergunta.
Jon Skeet
105

O problema com o uso literal de strings que eu acho é que ele pode fazer com que seu código pareça um pouco " estranho " porque, para não obter espaços na própria string, ele deve ficar completamente alinhado:

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

Que nojo.

Portanto, a solução que eu gosto de usar, que mantém tudo bem alinhado com o restante do seu código é:

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

E, é claro, se você apenas deseja dividir logicamente as linhas de uma instrução SQL como você é e realmente não precisa de uma nova linha, sempre pode substituir Environment.NewLine para " ".

dav_i
fonte
2
Muito mais limpo, obrigado. Além disso, o String.Concat funciona de maneira semelhante e não requer um separador.
Seth
Obrigado. Gosto do String.Join com o delimitador "" para SQL, pois permite a correspondência de indentação / parênteses e evita a necessidade de adicionar o espaço inicial.
Rob at TVSeries.com
7
Embora feia, a primeira versão não requer código para executar . A segunda opção obviamente possui uma sobrecarga de tempo de execução para concatenar as seqüências separadas.
Gone Coding
@GoneCoding, você tem certeza disso? O compilador pode otimizar a concatenação.
William Jockusch
@WilliamJockusch: geralmente as chamadas de funções que não são do operador (como junção) são deixadas intactas e não otimizadas. Melhor verificar o código compilado, mas eu colocaria o dinheiro que a chamada não é otimizada.
Gone Coding
104

Outra dica a se observar é o uso de literais de string em string.Format. Nesse caso, você precisa escapar de chaves / colchetes '{' 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)
Martin Clarke
fonte
14
E que diferença isso faz? Com ou sem "@", você precisa duplicar "{{" para obter "{" como caractere imprimível, é uma questão de String.Format, não de conteúdo da string.
greenoldman
12
É uma pegada notável para as pessoas que desejam colocar o código Javascript em uma string, o que pode ser feito com mais frequência em literais literal de strings do que em strings regulares.
Ed Brannin
2
No novo C # 6.0, você pode usar um operador de propriedade indexada junto com a literal literal da cadeia de caracteres (como este $ @ "O valor é {this.Value}";)
Heliac
2
@ Heliac Eu acho que você quer dizer que seqüências de caracteres interpoladas também podem ser literais com essa sintaxe. var query = $ @ "selecione foo, barra da tabela onde id = {id}";
Brianary 1/11
102

Como uma observação lateral, com o C # 6.0 agora você pode combinar cadeias interpoladas com a literal literal da cadeia de caracteres:

string camlCondition = $@"
<Where>
    <Contains>
        <FieldRef Name='Resource'/>
        <Value Type='Text'>{(string)parameter}</Value>
    </Contains>
</Where>";
Heliac
fonte
10
Legal, eu não sabia disso até agora. Se alguém estiver interessado: O $ thingy é chamado de "Interpolated Strings" e você pode ler sobre isso em detalhes aqui: msdn.microsoft.com/en-us/library/dn961160.aspx
Hauke ​​P.
tx, corrigiu a redação
Heliac 20/02
1
Suponho que uma chave literal literal deve ser dobrada, por exemplo, $@"{{example literal text { fooString }. }}" isso pode confundir alguns porque Angular, React e Vue.js usam a convenção oposta.
Patrick Szalapski
58

Por que as pessoas continuam confundindo seqüências com literais? A resposta aceita é uma ótima resposta para uma pergunta diferente; não para este.

Sei que esse é um tópico antigo, mas vim aqui com possivelmente a mesma pergunta do OP, e é frustrante ver como as pessoas continuam interpretando mal. Ou talvez eu esteja interpretando mal, não sei.

Grosso modo, uma string é uma região da memória do computador que, durante a execução de um programa, contém uma sequência de bytes que pode ser mapeada para caracteres de texto. Um literal de string, por outro lado, é um código-fonte, ainda não compilado, que representa o valor usado para inicializar um string posteriormente, durante a execução do programa em que ele aparece.

Em C #, a instrução ...

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

... não produz uma cadeia de três linhas, mas uma linha; a concatenação de três strings (cada uma inicializada de um literal diferente), nenhuma das quais contém um modificador de nova linha.

O que o OP parece estar perguntando - pelo menos o que eu perguntaria com essas palavras - não é como introduzir, na sequência compilada, quebras de linha que imitam as encontradas no código-fonte, mas como interromper a clareza por muito tempo. , uma única linha de texto no código-fonte sem introduzir quebras na sequência compilada. E sem exigir um tempo de execução estendido, juntei as várias substrings provenientes do código-fonte. Como as barras invertidas à direita dentro de uma cadeia de caracteres multilinha literal em javascript ou C ++.

Sugerir o uso de strings verbatim, funções esquecidas StringBuilder, String.Joins ou mesmo aninhadas com inversões de strings e o que não, me faz pensar que as pessoas não estão realmente entendendo a pergunta. Ou talvez eu não entenda.

Até onde eu sei, o C # não (pelo menos na versão paleolítica que ainda estou usando, da década anterior) possui um recurso para produzir de maneira limpa literais de cadeias multilinhas que podem ser resolvidas durante a compilação e não na execução.

Talvez as versões atuais o suportem, mas pensei em compartilhar a diferença que percebo entre strings e literais de strings.

ATUALIZAR:

(Do comentário de MeowCat2012) Você pode. A abordagem "+" do OP é a melhor. De acordo com as especificações, a otimização é garantida: http://stackoverflow.com/a/288802/9399618

Carvo Loco
fonte
1
A confusão que alguns (inclusive eu) podem ter tido em relação à pergunta original é que o formato aqui-doc (shell, php, perl, ...) inclui as novas linhas. Portanto, se o OP estiver comparando com o heredoc do PHP, incluir as novas linhas não deveria ter sido um problema.
Tanktalus 12/0318
Exatamente. Tanto quanto sei, sua resposta "não, você não pode fazer isso em C #" está correta.
TamaMcGlinn
Foi-me dito que em Java, uma string concatenada se tornaria uma única string literal no bytecode compilado. Talvez dot Net faça isso também?
Meow Cat 2012
2
Você pode. A abordagem "+" do OP é a melhor. De acordo com as especificações, a otimização é garantida: stackoverflow.com/a/288802/9399618 Ainda assim, você é um dos poucos a entender a questão. Seria possível remover ou dobrar respostas potencialmente enganosas, mas aceitas?
Meow Cat 2012
1
Obrigado pela dica, @ MeowCat2012. Olhando para algum código descompilado, parece que esse é realmente o caso.
Carvo Loco 24/07/19
12

Eu não vi isso, então vou publicá-lo aqui (se você estiver interessado em passar uma string, também pode fazê-lo.) A idéia é que você pode quebrar a string em várias linhas e adicionar seu próprio conteúdo (também em várias linhas) da maneira que desejar. Aqui "tableName" pode ser passado para a string.

    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
                                )";
    }
RobertHana
fonte
10
muito perigoso, eu diria: fácil para alguém fazer uma injeção de sql dessa maneira.
Kai
4
Tudo bem, desde que você saiba que todas as suas variáveis ​​(se houver!) Em sua string de consulta vêm de constantes de código ou de outra fonte segura - por exemplo, createTable("MyTable"); em qualquer caso, a pergunta do OP era sobre como inserir literais de strings de várias linhas diretamente no código , não como construir consultas de banco de dados em si. :)
dbeachy1
2
provavelmente deve usar um construtor de strings, especialmente se o número de vantagens (+) for muito.
Gdraphael
8

Você pode usar @ e "" .

        string sourse = @"{
        ""items"":[
        {
            ""itemId"":0,
            ""name"":""item0""
        },
        {
            ""itemId"":1,
            ""name"":""item1""
        }
        ]
    }";
vovkas
fonte
2
Você deve explicar o que significa cada um, como @ é para string literal e "" é para escapar aspas duplas.
AFract
4

Sim, você pode dividir uma string em várias linhas sem introduzir novas linhas na string real, mas isso é bonito:

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

O truque é introduzir o código que avalia vazio, e esse código pode conter novas linhas sem afetar a saída. Eu adaptei essa abordagem desta resposta a uma pergunta semelhante.

Aparentemente, existe alguma confusão sobre qual é a pergunta, mas há duas dicas de que o que queremos aqui é uma string literal que não contenha caracteres de nova linha, cuja definição abrange várias linhas. (nos comentários, ele diz isso, e "aqui está o que eu tenho" mostra código que não cria uma string com novas linhas)

Este teste de unidade mostra a intenção:

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

Altere a definição de consulta acima para que seja uma literal de seqüência de caracteres, em vez da concatenação de duas literais de seqüência de caracteres que podem ou não ser otimizadas em uma pelo compilador.

A abordagem do C ++ seria finalizar cada linha com uma barra invertida, fazendo com que o caractere da nova linha escape e não apareça na saída. Infelizmente, ainda existe o problema de que cada linha após a primeira deve ficar alinhada para não adicionar espaço em branco adicional ao resultado.

Há apenas uma opção que não depende de otimizações do compilador que podem não acontecer, que é colocar sua definição em uma linha. Se você deseja confiar nas otimizações do compilador, o + que você já possui é ótimo; você não precisa alinhar a string à esquerda, não obtém novas linhas no resultado, e é apenas uma operação, sem chamadas de função, para esperar a otimização.

TamaMcGlinn
fonte
1
Criativo. No entanto, parece que (não confirmado) isso seria tratado como uma sequência de formato e pode ou não ser otimizado. Por outro lado, a abordagem "+" do OP é a melhor. De acordo com as especificações, a otimização é garantida: stackoverflow.com/a/288802/9399618
Meow Cat 2012
4

Adicione várias linhas: use @

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

Adicione valores de cadeia ao meio: use $

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

Sequência de várias linhas Adicione valores ao meio: use $ @

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

Se você não deseja espaços / novas linhas, a adição de strings parece funcionar:

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.

Você pode executar o procedimento acima aqui, se quiser.

bandeja de ratos
fonte
2
Uma falha (demonstrada inadvertidamente) com essa abordagem é que você deve ter muito cuidado para incluir os espaços em que deseja. Eu recomendaria uma abordagem mais consistente do que a adotada (por exemplo, sempre no início da linha).
rattray
string + string é exatamente com o que o OP começou.
TamaMcGlinn
1

Sei que estou um pouco atrasado para a festa, mas quero recomendar https://www.buildmystring.com/ para futuros leitores deste tópico. Você pode converter qualquer código em literal de string C # usando este site.

aadi1295
fonte
-10

Você pode usar estes dois métodos:

    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();
    }

No SplitLineToMultiline (), você precisa definir a string que deseja usar e o comprimento da linha, é muito simples. Obrigado .

nassimlouchani
fonte