Многострочный строковый литерал в C #

1050

Есть ли простой способ создать многострочный строковый литерал в C #?

Вот что у меня сейчас:

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

Я знаю, что PHP имеет

<<<BLOCK

BLOCK;

Есть ли в C # нечто подобное?

Chet
источник
1
В вашем примере нет разрывов строк. Ты хочешь их?
Воскресенье
8
Нет. Я хотел только несколько строк для наглядности / чистоты кода.
Чет
6
В этом случае дословные строки содержат разрывы строк. Вы можете использовать @ "...". Заменить (Environment.NewLine, ""), если хотите.
Воскресенье,
9
Вам следует рассмотреть возможность связывания параметра 42как параметра, особенно если он поступает от пользовательского ввода, чтобы избежать внедрения SQL.
Йенс Мюленхофф
@ JensMühlenhoff, как кто-то вставит жестко запрограммированную строку, которая определена в коде?
Мистер Бой

Ответы:

1594

Вы можете использовать @символ перед буквой a stringдля формирования буквального строкового литерала :

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

Вам также не нужно экранировать специальные символы при использовании этого метода, за исключением двойных кавычек, как показано в ответе Джона Скита.

Джон Раш
источник
43
В любом случае это строковый литерал - это дословный строковый литерал со знаком @.
Джон Скит
95
если ваша строка содержит двойные кавычки ("), вы можете избежать их следующим образом:" "(то есть два символа двойной кавычки)
Muad'Dib
8
Есть ли способ сделать это без создания новых строк? У меня есть очень длинный фрагмент текста, который я хотел бы видеть в IDE без использования плюса («привет» + «там»).
noelicus 12.12.12
2
@noelicus - не совсем, но вы можете обойти это, используя описанную выше технику Вейкура:@"my string".Replace(Environment.NewLine, "")
Джон Раш
8
@afsharm Вы можете использовать $ @ "текст"
Патрик Макдональд
567

В C # он называется дословным строковым литералом , и просто нужно поставить @ перед литералом. Это не только позволяет использовать несколько строк, но и отключает экранирование. Так, например, вы можете сделать:

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

Однако это включает в себя разрывы строк (используя любой перевод строки, в котором они есть у вашего источника) в строку. Для SQL это не только безвредно, но, вероятно, улучшает читабельность везде, где вы видите строку - но в других местах это может не потребоваться, и в этом случае вам не нужно будет использовать многострочный дословный строковый литерал для начала, или удалите их из полученной строки.

Единственное, что можно избежать - это то, что если вам нужна двойная кавычка, вам нужно добавить дополнительный символ двойной кавычки:

string quote = @"Jon said, ""This will work,"" - and it did!";
Джон Скит
источник
2
Этот ответ неверен; он вводит новые строки, которые OP не желает.
TamaMcGlinn
@TamaMcGlinn: Я добавлю кое-что в ответ об этом - не было ясно, когда ОП написал вопрос.
Джон Скит
105

Я обнаружил, что проблема с использованием строкового литерала заключается в том, что он может сделать ваш код немного странным, потому что для того, чтобы не получить пробелы в самой строке, он должен быть полностью выровнен по левому краю:

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

Тьфу.

Итак, решение, которое мне нравится использовать, которое сохраняет все хорошо выровненным с остальным кодом:

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

И, конечно, если вы просто хотите , чтобы логически разделить строки оператора SQL , как вы и на самом деле не нужна новая линия, вы всегда можете просто заменить Environment.NewLineна " ".

dav_i
источник
2
Гораздо чище, спасибо. Кроме того, String.Concat работает аналогично и не требует разделителя.
Сет
Спасибо. Мне нравится String.Join с разделителем "" для SQL, поскольку он допускает отступы / совпадения парен и не требует добавления начального пробела.
Роб на TVSeries.com
7
Хотя уродливая, первая версия не требует кода для запуска . Второй вариант, очевидно, имеет накладные расходы времени выполнения для объединения отдельных строк.
Ушел кодирование
@ GoneCoding, ты уверен в этом? Компилятор может оптимизировать конкатенацию.
Уильям Джокуш
@WilliamJockusch: как правило, вызовы неоператорных функций (например, соединение) остаются без изменений и не оптимизируются. Лучше всего проверить скомпилированный код, но я бы положил деньги на то, что вызов не оптимизирован.
Ушел кодирование
104

Еще один недостаток, на который стоит обратить внимание - это использование строковых литералов в string.Format. В этом случае вам нужно избегать фигурных скобок / скобок '{' и '}'.

// 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
И какая разница? С или без "@" вы должны удвоить "{{", чтобы получить "{" в качестве печатного символа, это вопрос String.Format, а не строкового содержимого.
Гринольдман
12
Это замечательное замечание для людей, которые хотят поместить код Javascript в строку, что чаще всего делается в дословных строковых литералах, чем в обычных строках.
Эд Браннин
2
В новом C # 6.0 вы можете использовать оператор индексированного свойства вместе с буквальным строковым литералом (например, $ @ "Value is {this.Value}";)
Heliac
2
@ Helic Я думаю, вы имеете в виду, что интерполированные строки также могут быть буквальными с этим синтаксисом. var query = $ @ "выберите foo, бар из таблицы, где id = {id}";
brianary
102

Как примечание: с C # 6.0 теперь вы можете комбинировать интерполированные строки с буквальным строковым литералом:

string camlCondition = $@"
<Where>
    <Contains>
        <FieldRef Name='Resource'/>
        <Value Type='Text'>{(string)parameter}</Value>
    </Contains>
</Where>";
совпадающий с восходом солнца
источник
10
Круто, я не знал об этом до сих пор. Если кому-то интересно: $ thingy называется «Интерполированные строки», и вы можете прочитать об этом подробно здесь: msdn.microsoft.com/en-us/library/dn961160.aspx
Hauke ​​P.
TX, исправил формулировку
Heliac
1
Я предполагаю, что буквенная фигурная скобка должна быть удвоена, например, $@"{{example literal text { fooString }. }}" это может сбить некоторых с толку, потому что Angular, React и Vue.js используют противоположное соглашение.
Патрик Салапски
58

Почему люди продолжают путать строки со строковыми литералами? Принятый ответ - отличный ответ на другой вопрос; не к этому.

Я знаю, что это старая тема, но я пришел сюда, возможно, с тем же вопросом, что и ОП, и мне неприятно видеть, как люди продолжают неправильно его читать. Или, может быть, я неправильно понимаю, я не знаю.

Грубо говоря, строка - это область компьютерной памяти, которая во время выполнения программы содержит последовательность байтов, которые могут быть сопоставлены с текстовыми символами. Строковый литерал, с другой стороны, является частью исходного кода, еще не скомпилированного, который представляет значение, используемое для инициализации строки позже, во время выполнения программы, в которой она появляется.

В C # утверждение ...

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

... не создает строку из трех строк, а содержит одну строку; конкатенация трех строк (каждая инициализируется из другого литерала), ни одна из которых не содержит модификатор новой строки.

Похоже, что OP спрашивает - по крайней мере, то, что я хотел бы спросить с этими словами - не о том, как ввести в скомпилированную строку разрывы строк, которые имитируют найденные в исходном коде, а о том, как разбить для большей ясности. одиночная строка текста в исходном коде без разрывов в скомпилированной строке. И не требуя расширенного времени выполнения, потратил на объединение нескольких подстрок из исходного кода. Как и обратные косые черты внутри многострочного строкового литерала в javascript или C ++.

Предлагая использовать дословные строки, неважно StringBuilders, String.Joins или даже вложенные функции с инверсией строк, а что нет, я думаю, что люди не совсем понимают вопрос. Или, может быть, я не понимаю этого.

Насколько я знаю, C # не имеет (по крайней мере, в палеолитической версии, которую я все еще использую, из предыдущего десятилетия) функцию чистой генерации многострочных строковых литералов, которые могут быть разрешены во время компиляции, а не выполнения.

Возможно, текущие версии поддерживают это, но я подумал, что поделюсь разницей между строками и строковыми литералами.

ОБНОВИТЬ:

(Из комментария MeowCat2012) Вы можете. Подход «+» от OP - лучший. Согласно спецификации, оптимизация гарантирована: http://stackoverflow.com/a/288802/9399618

Карво Локо
источник
1
Путаница, которую некоторые (включая меня), возможно, имели при взгляде на первоначальный вопрос, заключается в том, что формат here-doc (shell, php, perl, ...) включает переводы строки. Так что, если OP сравнивает с heredoc PHP, то включение новых строк не должно было быть проблемой.
Tanktalus
Точно. Насколько я знаю, ваш ответ "нет, вы не можете сделать это в C #" является правильным.
TamaMcGlinn
Мне сказали, что в Java такая объединенная строка станет слитным литералом в скомпилированном байт-коде. Может быть, точка Net сделать так же?
Мяу Кошка 2012
2
Вы можете. Подход «+» от OP - лучший. Согласно спецификации, оптимизация гарантирована: stackoverflow.com/a/288802/9399618 Тем не менее, вы один из немногих понимаете вопрос. Можно ли убрать или сложить потенциально вводящие в заблуждение, но принятые ответы?
Мяу Кот 2012
1
Спасибо за подсказку, @ MeowCat2012. Глядя на некоторый декомпилированный код, кажется, что это действительно так.
Карво Локо
12

Я не видел этого, поэтому я опубликую это здесь (если вы заинтересованы в передаче строки, вы также можете сделать это). Идея состоит в том, что вы можете разбить строку на несколько строк и добавить свой собственный контент (также на нескольких строках) любым способом, каким пожелаете. Здесь «tableName» может быть передано в строку.

    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
источник
10
довольно опасно, я бы сказал: легко кому-то сделать инъекции sql таким способом.
Кай
4
Это нормально, если вы знаете, что все ваши переменные (если таковые имеются!) В строке запроса происходят из констант кода или другого безопасного источника - например, createTable("MyTable"); в любом случае вопрос ОП заключался в том, как вводить многострочные строковые литералы непосредственно в коде , а не как строить запросы к базе данных как таковые. :)
dbeachy1
2
Вероятно, следует использовать построитель строк, особенно если количество плюсов (+) много.
Gldraphael
8

Вы можете использовать @ и "" .

        string sourse = @"{
        ""items"":[
        {
            ""itemId"":0,
            ""name"":""item0""
        },
        {
            ""itemId"":1,
            ""name"":""item1""
        }
        ]
    }";
vovkas
источник
2
Вы должны объяснить, что делает каждый, так как @ для дословной строки, а "" для экранирования двойных кавычек.
ПОЗДРАВЛЯЙ
4

Да, вы можете разбить строку на несколько строк, не вводя новые строки в фактическую строку, но это не очень красиво:

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

Хитрость заключается в том, чтобы ввести код, который оценивается как пустой, и этот код может содержать символы новой строки, не влияя на вывод. Я адаптировал этот подход из этого ответа к аналогичному вопросу.

Очевидно, существует некоторая путаница относительно вопроса, но есть два намека на то, что нам нужен строковый литерал, не содержащий символов новой строки, определение которого состоит из нескольких строк. (в комментариях он так говорит, и «вот что у меня есть» показывает код, который не создает строку с символами новой строки в ней)

Этот модульный тест показывает намерение:

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

Измените приведенное выше определение запроса так, чтобы он представлял собой один строковый литерал вместо объединения двух строковых литералов, которые могут быть оптимизированы или не оптимизированы компилятором в один.

Подход C ++ заключался бы в том, чтобы завершать каждую строку обратной косой чертой, в результате чего символ новой строки экранировался и не появлялся в выходных данных. К сожалению, все еще существует проблема, заключающаяся в том, что каждая строка после первой должна быть выровнена, чтобы не добавлять дополнительные пробелы к результату.

Есть только одна опция, которая не зависит от оптимизации компилятора, которая может не произойти, - это поместить ваше определение в одну строку. Если вы хотите положиться на оптимизацию компилятора, то +, который у вас уже есть, великолепен; вам не нужно выравнивать строку по левому краю, вы не получаете новых строк в результате, и это всего лишь одна операция, без вызовов функций, чтобы ожидать оптимизации.

TamaMcGlinn
источник
1
Творческий. Однако кажется, что (не подтверждено) это будет рассматриваться как строка формата и может быть оптимизировано или не оптимизировано. С другой стороны, подход «+» от OP является лучшим. Согласно спецификации, оптимизация гарантирована: stackoverflow.com/a/288802/9399618
Meow Cat 2012,
4

Добавьте несколько строк: используйте @

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

Добавьте строковые значения в середину: используйте $

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

Многострочная строка Добавьте значения в середину: используйте $ @

string text ="Customer";
string query = $@"SELECT foo, bar
FROM {text}Table
WHERE id = 42";
Исанка Талагала
источник
3

Если вам не нужны пробелы / переводы строк, кажется, что добавление строк работает:

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.

Вы можете запустить выше здесь, если хотите.

Rattray
источник
2
Один (непреднамеренно продемонстрированный) недостаток этого подхода заключается в том, что вы должны быть очень осторожны, чтобы включать места, где вы хотите их. Я бы рекомендовал более последовательный подход, чем я выбрал (например, всегда в начале строки).
rattray
Строка + строка - только то, с чего OP начал.
TamaMcGlinn
1

Я знаю, что немного опоздал на вечеринку, но хочу порекомендовать https://www.buildmystring.com/ для будущих читателей этой темы. С помощью этого сайта вы можете конвертировать любой код в строковый литерал C #.

aadi1295
источник
-10

Вы можете использовать это двумя способами:

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

В SplitLineToMultiline () вам нужно определить строку, которую вы хотите использовать, и длину строки, это очень просто. Спасибо .

nassimlouchani
источник