Лінійний рядок у рядку C #


1046

Чи є простий спосіб створити багаторядковий літеральний рядок у C #?

Ось що я маю зараз:

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

Я знаю, PHP має

<<<BLOCK

BLOCK;

У C # є щось подібне?


1
У вашому прикладі немає розривів рядків. Ви їх хочете?
weiqure

8
Ні. Я хотів лише декількох рядків з міркувань чистоти коду та видимості.
Чет

6
У цьому випадку дослівні рядки містять розриви рядків. Ви можете використовувати @ "...". Замініть (Environment.NewLine, ""), якщо хочете.
weiqure

9
Вам слід розглянути прив'язку параметра 42як параметра, особливо якщо він надходить із введення користувача, щоб уникнути ін'єкції SQL.
Єнс Мюленхофф

@ JensMühlenhoff, як хтось вставить жорстко закодовану рядок, що визначено в коді?
Пан Хлопчик

Відповіді:


1587

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

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

Також вам не доведеться уникати спеціальних символів при використанні цього методу, за винятком подвійних лапок, як показано у відповіді Джона Скіта.


43
У будь-якому випадку це рядковий літерал - це дослівний рядковий буквальний знак зі знаком @.
Джон Скіт

95
якщо ваш рядок містить подвійні лапки ("), ви можете уникнути їх так:" "(це два символи з подвійною цитатами)
Muad'Dib

8
Чи існує спосіб зробити вищезазначене, не створюючи нових ліній? У мене дійсно довгий фрагмент тексту, який я хотів би побачити загорнутим у IDE, не використовуючи плюс ("привіт" + "там").
noelicus

2
@noelicus - не дуже, але ви могли б це вирішити, використовуючи техніку weiqure вище:@"my string".Replace(Environment.NewLine, "")
Джон Раш

8
@afsharm Ви можете використовувати $ @ "text"
Патрік Макдональд,

566

Це називається дослівним рядковим літеральним рядком в C #, і це лише питання поставити @ перед літералом. Це не тільки дозволяє кілька рядків, але також вимикає втечу. Так, наприклад, ви можете зробити:

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

Сюди ж включаються розриви рядків (використовуючи будь-який розрив рядка, який має ваше джерело, як) в рядок. Для SQL це не тільки нешкідливо, але, ймовірно, покращує читабельність у будь-якому місці, де ви бачите рядок - але в інших місцях вона може не знадобитися, і в цьому випадку вам потрібно буде не використовувати багаторядковий дослівний рядковий рядковий рядок для початку, або видаліть їх із отриманого рядка.

Єдиний біг втечі - це те, що якщо вам потрібна подвійна цитата, вам потрібно додати додатковий символ подвійної цитати:

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

2
Ця відповідь невірна; він вводить нові лінії, яких ОП не бажає.
TamaMcGlinn

@TamaMcGlinn: Я додам щось у відповідь на це - не було зрозуміло, коли ОП написало питання.
Джон Скіт

105

Проблема з використанням рядкового літералу, який я вважаю, полягає в тому, що він може зробити ваш код трохи " дивним ", оскільки для того, щоб не отримати пробілів у самій рядку, його слід повністю вирівняти:

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

Гидота.

Тож рішення, яке мені подобається використовувати, яке підтримує все чітке узгодження з рештою вашого коду:

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

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


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, а не рядковий вміст.
greenoldman

12
Це помітна готча для людей, які хочуть вводити Javascript-код у рядок, що може бути зроблено частіше у дослівних рядкових літералах, ніж у звичайних рядках.
Ед Браннін

2
У новому C # 6.0 ви можете використовувати індексований оператор властивостей разом з дослівно-рядковим рядковим літералом (наприклад, це $ @ "Значення є {this.Value}";)
Heliac

2
@Heliac Я думаю, ви маєте на увазі, що інтерпольовані рядки також можуть бути буквальними з цим синтаксисом. var query = $ @ "виберіть foo, рядок із таблиці, де id = {id}";
бріанарі

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, виправлено формулювання
Геліак

1
Я припускаю, що буквальна фігурна дужка тоді повинна бути подвоєна, наприклад, $@"{{example literal text { fooString }. }}" це може дещо збити з пантелику, оскільки Angular, React і Vue.js використовують протилежну умову.
Патрік Шалапський

58

Чому люди продовжують плутати рядки з рядковими літералами? Прийнята відповідь - це чудова відповідь на інше питання; не до цього.

Я знаю, що це стара тема, але я приїхав сюди, можливо, з тим же питанням, що і з ОП, і мені неприємно бачити, як люди продовжують її неправильно читати. А може, я його неправильно читаю, не знаю.

Грубо кажучи, рядок - це область комп'ютерної пам’яті, яка під час виконання програми містить послідовність байтів, які можуть бути відображені в текстові символи. З іншого боку, рядковий літерал - це ще не скомпільований фрагмент вихідного коду, який представляє значення, яке використовується для ініціалізації рядка пізніше під час виконання програми, в якій він відображається.

У C # заява ...

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

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

Здається, що ОП запитує - принаймні, про що я б запитав цими словами - це не те, як ввести в складений рядок розриви рядків, що імітують тих, що знаходяться у вихідному коді, а як довго розбиватися на ясність , єдиний рядок тексту у вихідному коді без введення перерв у складеному рядку. І не вимагаючи збільшення часу виконання, витрачаючи на приєднання до декількох підрядів, що надходять із вихідного коду. Як і зворотні косої риски в лінійному рядку рядків у javascript або C ++.

Запропонуючи використання дослідних рядків, не зважаючи на функції StringBuilders, String.Joins або навіть вкладені функції з обертанням рядків і що ні, змушує мене думати, що люди не дуже розуміють питання. А може, я цього не розумію.

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

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

ОНОВЛЕННЯ:

(З коментаря MeowCat2012) Можна. Підхід «+» від ОП є найкращим. Відповідно до специфікації, оптимізація гарантована: http://stackoverflow.com/a/288802/9399618


1
Плутанина, з якою деякі (в тому числі і я), мабуть, дивилася на початкове запитання, полягає в тому, що формат here-doc (оболонка, php, perl, ...) включає нові рядки. Отже, якщо ОП порівнюється з гередоком PHP, то включення нових рядків не повинно було бути проблемою.
Танкталус

Саме так. Наскільки я знаю, ваша відповідь «ні, ви не можете цього зробити на C #» є правильною.
TamaMcGlinn

Мені сказали, що в Java такий зв'язаний рядок стане однорядним літералом у складеному байтовому коді. Можливо, так це роблять і Net Net?
Meow Cat 2012

2
Ти можеш. Підхід «+» від ОП є найкращим. Відповідно до специфікації, оптимізація гарантована: stackoverflow.com/a/288802/9399618 Ти все ж один із небагатьох, хто розуміє це питання. Чи можна було б видалити чи скласти потенційно оманливі, але прийняті відповіді?
Meow Cat 2012

1
Дякую за підказку, @ MeowCat2012. Дивлячись на якийсь декомпільований код, здається, що це дійсно так.
Carvo Loco

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

10
досить небезпечно, я б сказав: комусь легко зробити sql-ін’єкції таким чином.
Кай

4
Це добре, якщо ви знаєте, що всі ваші змінні (якщо такі є!) У вашій рядку запиту походять від констант коду чи іншого безпечного джерела - наприклад, createTable("MyTable"); у будь-якому випадку питання ОП полягало у тому, як вводити багаторядкові літеральні рядки безпосередньо в код , а не як будувати запити до бази даних самі по собі :)
dbeachy1

2
Мабуть, слід скористатися конструктором струн, особливо якщо кількість плюсів (+) велика.
gldraphael

8

Ви можете використовувати @ і "" .

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

2
Ви повинні пояснити, що робить кожен, так як @ - це дослідна рядок, а "" - це уникнути подвійних лапок.
AFAct

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 ++ полягатиме в тому, щоб закінчити кожен рядок з зворотною косою рисою, що призведе до того, що символ нового рядка буде уникнути і не з’явиться у висновку. На жаль, все ще виникає проблема, що кожен рядок після першого повинен залишатися вирівнюваним, щоб не додати додатковий пробіл до результату.

Є лише один варіант, який не покладається на оптимізацію компілятора, яка може не відбутися, а саме - поставити своє визначення в один рядок. Якщо ви хочете покластися на оптимізацію компілятора, + у вас вже є великий; вам не доведеться вирівнювати рядок ліворуч, ви не отримуєте нові рядки в результаті, і очікувати оптимізації потрібно лише одну операцію, без викликів функцій.


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.

Ви можете запустити вищезазначене тут, якщо хочете.


2
Один (ненавмисне продемонстрований) недолік такого підходу полягає в тому, що вам потрібно бути дуже обережними, щоб включити пробіли там, де ви їх хочете. Я рекомендую більш послідовний підхід, ніж я застосовував (наприклад, завжди на початку рядка).
rattray

string + string - це саме те, з чого розпочався ОП.
TamaMcGlinn

1

Я знаю, що я трохи спізнююся на вечірку, але хочу рекомендувати https://www.buildmystring.com/ для майбутніх читачів цієї теми. Ви можете конвертувати будь-який код у C # string literal за допомогою цього сайту.


-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 () вам потрібно визначити рядок, який ви хочете використовувати, і довжину рядка, це дуже просто. Дякую .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.