String string multiline dalam C #

1046

Apakah ada cara mudah untuk membuat string multiline literal dalam C #?

Inilah yang saya miliki sekarang:

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

Saya tahu PHP punya

<<<BLOCK

BLOCK;

Apakah C # memiliki sesuatu yang serupa?

Chet
sumber
1
Tidak ada jeda baris dalam contoh Anda. Apa kamu menginginkan mereka?
weiqure
8
Tidak. Saya hanya ingin beberapa baris untuk alasan kebersihan visibilitas / kode.
Chet
6
Dalam hal ini, string kata demi kata mengandung garis yang terputus. Anda dapat menggunakan @ "...". Ganti (Environment.NewLine, "") jika Anda suka.
weiqure
9
Anda harus mempertimbangkan mengikat 42sebagai parameter, terutama jika itu berasal dari input pengguna, untuk menghindari injeksi SQL.
Jens Mühlenhoff
@ JensMühlenhoff bagaimana seseorang akan menyuntikkan string hard-coded, yang didefinisikan dalam kode?
Tn. Boy

Jawaban:

1590

Anda bisa menggunakan @simbol di depan a stringuntuk membentuk string string kata demi kata :

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

Anda juga tidak perlu melarikan diri karakter khusus ketika Anda menggunakan metode ini, kecuali untuk tanda kutip ganda seperti yang ditunjukkan dalam jawaban Jon Skeet.

John Rasch
sumber
43
Ini adalah string literal - string literal kata kunci dengan tanda @.
Jon Skeet
95
jika string Anda mengandung tanda kutip ganda ("), Anda dapat menghindarinya seperti:" "(itulah dua karakter tanda kutip ganda)
Muad'Dib
8
Apakah ada cara melakukan hal di atas tanpa membuat garis baru? Saya memiliki teks yang sangat panjang yang ingin saya lihat terbungkus dalam IDE tanpa harus menggunakan plus ("hai" + "di sana").
noelicus
2
@noelicus - tidak juga, tetapi Anda bisa mengatasinya dengan menggunakan teknik weiqure di atas:@"my string".Replace(Environment.NewLine, "")
John Rasch
8
@afsharm Anda dapat menggunakan $ @ "text"
Patrick McDonald
566

Ini disebut string kata demi kata literal dalam C #, dan itu hanya masalah menempatkan @ sebelum literal. Ini tidak hanya memungkinkan beberapa baris, tetapi juga mematikan melarikan diri. Jadi misalnya bisa Anda lakukan:

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

Ini termasuk jeda baris (menggunakan apa pun jeda baris sumber Anda memilikinya) ke dalam string, namun. Untuk SQL, itu tidak hanya tidak berbahaya, tetapi mungkin meningkatkan keterbacaan di mana pun Anda melihat string - tetapi di tempat lain mungkin tidak diperlukan, dalam hal ini Anda tidak perlu menggunakan string multi-baris kata demi kata untuk memulai, atau menghapusnya dari string yang dihasilkan.

Satu-satunya jalan keluar adalah jika Anda ingin penawaran ganda, Anda harus menambahkan simbol penawaran ganda tambahan:

string quote = @"Jon said, ""This will work,"" - and it did!";
Jon Skeet
sumber
2
Jawaban ini salah; memperkenalkan baris baru yang tidak diinginkan OP.
TamaMcGlinn
@TamaMcGlinn: Saya akan menambahkan sesuatu ke dalam jawaban tentang itu - tidak jelas kapan OP menulis pertanyaan.
Jon Skeet
105

Masalah dengan menggunakan string literal yang saya temukan adalah dapat membuat kode Anda terlihat sedikit " aneh " karena untuk tidak mendapatkan spasi dalam string itu sendiri, itu harus sepenuhnya dibariskan:

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

Yuck.

Jadi solusi yang saya suka gunakan, yang menjaga semuanya tetap selaras dengan sisa kode Anda adalah:

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

Dan tentu saja, jika Anda hanya ingin secara logis berpisah baris pernyataan SQL seperti Anda dan tidak benar-benar membutuhkan baris baru, Anda dapat selalu hanya pengganti Environment.NewLineuntuk " ".

dav_i
sumber
2
Jauh lebih bersih, terima kasih. Juga, String.Concat bekerja dengan cara yang sama dan tidak memerlukan pemisah.
Seth
Terima kasih. Saya suka String.Gabung dengan pembatas "" untuk SQL karena memungkinkan untuk indentasi / pencocokan paren dan menghindari harus menambahkan ruang terkemuka.
Rob di TVSeries.com
7
Meskipun jelek, versi pertama tidak memerlukan kode untuk dijalankan . Opsi kedua jelas memiliki overhead run-time untuk menggabungkan string terpisah.
Hilang Coding
@GoneCoding, Anda yakin tentang itu? Kompiler dapat mengoptimalkan penggabungan.
William Jockusch
@ WilliamJockusch: umumnya panggilan fungsi non-operator (seperti bergabung) dibiarkan utuh, dan tidak dioptimalkan. Terbaik memeriksa kode yang dikompilasi tetapi saya akan meletakkan uang bahwa panggilan tidak dioptimalkan.
Hilang Coding
104

Satu gotcha lain yang harus diperhatikan adalah penggunaan string literal dalam string.Format. Dalam hal ini Anda perlu melepaskan kurung kurawal / kurung '{' dan '}'.

// 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
sumber
14
Dan apa bedanya? Dengan atau tanpa "@" Anda harus menggandakan "{{" untuk mendapatkan "{" sebagai karakter yang dapat dicetak, itu adalah masalah String.Format, bukan konten string.
greenoldman
12
Ini adalah gotcha yang terkenal bagi orang-orang yang ingin memasukkan kode Javascript dalam sebuah string, yang dapat dilakukan lebih sering dalam string literal kata demi kata daripada string biasa.
Ed Brannin
2
Di C # 6.0 baru, Anda dapat menggunakan operator properti yang diindeks bersama-sama dengan string literal kata demi kata (seperti ini $ @ "Nilai is {this.Value}";)
Heliac
2
@Heliac Saya pikir maksud Anda string interpolasi juga bisa secara literal dengan sintaks itu. var query = $ @ "pilih foo, bar dari tabel di mana id = {id}";
brianary
102

Sebagai catatan tambahan, dengan C # 6.0 Anda sekarang dapat menggabungkan string interpolasi dengan string literal kata demi kata:

string camlCondition = $@"
<Where>
    <Contains>
        <FieldRef Name='Resource'/>
        <Value Type='Text'>{(string)parameter}</Value>
    </Contains>
</Where>";
Matahari
sumber
10
Keren, saya tidak tahu tentang ini sampai sekarang. Jika ada yang tertarik: $ thingy disebut "Interpolated Strings" dan Anda dapat membacanya secara detail di sini: msdn.microsoft.com/en-us/library/dn961160.aspx
Hauke ​​P.
tx, perbaiki kata-katanya
Heliac
1
Saya berasumsi kurung kurawal literal kemudian harus digandakan, misalnya $@"{{example literal text { fooString }. }}" Ini mungkin membingungkan beberapa karena Angular, React, dan Vue.js menggunakan konvensi yang berlawanan.
Patrick Szalapski
58

Mengapa orang membuat string yang membingungkan dengan string literal? Jawaban yang diterima adalah jawaban yang bagus untuk pertanyaan yang berbeda; tidak untuk yang satu ini.

Saya tahu ini adalah topik lama, tetapi saya datang ke sini dengan kemungkinan pertanyaan yang sama dengan OP, dan sangat frustasi melihat orang-orang terus salah membaca. Atau mungkin saya salah membaca, saya tidak tahu.

Secara kasar, string adalah wilayah memori komputer yang, selama eksekusi program, berisi urutan byte yang dapat dipetakan ke karakter teks. String literal, di sisi lain, adalah sepotong kode sumber, belum dikompilasi, yang mewakili nilai yang digunakan untuk menginisialisasi string nanti, selama eksekusi program di mana ia muncul.

Dalam C #, pernyataan ...

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

... tidak menghasilkan string tiga baris tetapi satu liner; gabungan tiga string (masing-masing diinisialisasi dari literal berbeda) tidak ada yang berisi pengubah baris baru.

Apa yang tampaknya ditanyakan OP - setidaknya apa yang akan saya tanyakan dengan kata-kata itu - bukanlah bagaimana memperkenalkan, dalam string yang dikompilasi, jeda baris yang meniru yang ditemukan dalam kode sumber, tetapi bagaimana memecah untuk kejelasan yang lama , satu baris teks dalam kode sumber tanpa memperkenalkan jeda dalam string yang dikompilasi. Dan tanpa memerlukan waktu eksekusi yang panjang, dihabiskan untuk bergabung dengan beberapa substring yang berasal dari kode sumber. Seperti garis miring terbalik dalam string multiline literal dalam javascript atau C ++.

Menyarankan penggunaan string kata demi kata, fungsi Nevermind StringBuilder, String.Joins atau bahkan bersarang dengan pembalikan string dan apa yang tidak, membuat saya berpikir bahwa orang tidak benar-benar memahami pertanyaan. Atau mungkin saya tidak memahaminya.

Sejauh yang saya tahu, C # tidak (setidaknya dalam versi paleolitik saya masih menggunakan, dari dekade sebelumnya) memiliki fitur untuk bersih hasil multiline string yang literal yang dapat diselesaikan selama kompilasi daripada eksekusi.

Mungkin versi saat ini mendukungnya, tapi saya pikir saya akan berbagi perbedaan yang saya rasakan antara string dan literal string.

MEMPERBARUI:

(Dari komentar MeowCat2012) Anda bisa. Pendekatan "+" oleh OP adalah yang terbaik. Menurut spek optimisasi dijamin: http://stackoverflow.com/a/288802/9399618

Carvo Loco
sumber
1
Kebingungan beberapa (termasuk saya) mungkin telah melihat pertanyaan asli adalah bahwa format di sini-doc (shell, php, perl, ...) termasuk baris baru. Jadi jika OP membandingkan dengan heredoc PHP, maka memasukkan baris baru seharusnya tidak menjadi masalah.
Tanktalus
Persis. Sejauh yang saya tahu, jawaban Anda "tidak, Anda tidak dapat melakukan ini dalam C #" benar.
TamaMcGlinn
Saya diberitahu bahwa di Jawa, string bersambung seperti itu akan menjadi string tunggal literal dalam bytecode yang dikompilasi. Mungkin dot Net juga melakukannya?
Kucing Meow 2012
2
Kamu bisa. Pendekatan "+" oleh OP adalah yang terbaik. Menurut spek optimisasi dijamin: stackoverflow.com/a/288802/9399618 Masih Anda salah satu dari sedikit memahami pertanyaan. Apakah mungkin untuk menghapus atau melipat jawaban yang berpotensi menyesatkan tetapi diterima?
Meow Cat 2012
1
Terima kasih atas petunjuknya, @ MeowCat2012. Melihat beberapa kode yang di-decompile, tampaknya memang demikian.
Carvo Loco
12

Saya belum melihat ini, jadi saya akan mempostingnya di sini (jika Anda tertarik untuk melewatkan string Anda dapat melakukan ini juga.) Idenya adalah bahwa Anda dapat memecah string pada beberapa baris dan menambahkan konten Anda sendiri (juga pada banyak baris) dengan cara apa pun yang Anda inginkan. Di sini "tableName" dapat diteruskan ke 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
sumber
10
cukup berbahaya saya akan mengatakan: mudah bagi seseorang untuk membuat sql-injeksi seperti itu
Kai
4
Tidak masalah selama Anda tahu bahwa semua variabel Anda (jika ada!) Dalam string kueri Anda berasal dari konstanta kode atau sumber aman lainnya - misalnya, createTable("MyTable"); Dalam kasus apa pun, pertanyaan OP adalah tentang bagaimana memasukkan string string multiline langsung dalam kode , bukan bagaimana membangun kueri basis data per se. :)
dbeachy1
2
mungkin harus menggunakan pembuat string, terutama jika jumlah plus (+) banyak.
gldraphael
8

Anda dapat menggunakan @ dan "" .

        string sourse = @"{
        ""items"":[
        {
            ""itemId"":0,
            ""name"":""item0""
        },
        {
            ""itemId"":1,
            ""name"":""item1""
        }
        ]
    }";
vovkas
sumber
2
Anda harus menjelaskan apa yang dilakukan masing-masing, karena @ adalah untuk string kata demi kata dan "" untuk menghindari kutip ganda.
AFract
4

Ya, Anda dapat membagi string ke beberapa baris tanpa memasukkan baris baru ke string yang sebenarnya, tetapi tidak cantik:

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

Caranya adalah dengan memperkenalkan kode yang mengevaluasi kosong, dan kode itu mungkin berisi baris baru tanpa mempengaruhi output. Saya mengadaptasi pendekatan ini dari jawaban ini ke pertanyaan serupa.

Tampaknya ada beberapa kebingungan mengenai apa pertanyaannya, tetapi ada dua petunjuk bahwa yang kita inginkan di sini adalah string literal yang tidak mengandung karakter baris baru, yang definisinya mencakup beberapa baris. (di komentar dia bilang begitu, dan "ini yang saya punya" menunjukkan kode yang tidak membuat string dengan baris baru di dalamnya)

Tes unit ini menunjukkan maksud:

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

Ubah definisi kueri di atas sehingga menjadi satu string literal, alih-alih gabungan dua literal string yang mungkin atau mungkin tidak dioptimalkan menjadi satu oleh kompiler.

Pendekatan C ++ adalah untuk mengakhiri setiap baris dengan garis miring terbalik, menyebabkan karakter baris baru untuk melarikan diri dan tidak muncul dalam output. Sayangnya, masih ada masalah bahwa setiap baris setelah yang pertama harus dibariskan agar tidak menambahkan spasi tambahan ke hasilnya.

Hanya ada satu opsi yang tidak bergantung pada optimisasi kompiler yang mungkin tidak terjadi, yaitu menempatkan definisi Anda pada satu baris. Jika Anda ingin mengandalkan optimisasi kompiler, + yang sudah Anda miliki sangat bagus; Anda tidak perlu menyelaraskan kiri string, Anda tidak mendapatkan baris baru di hasilnya, dan itu hanya satu operasi, tidak ada panggilan fungsi, untuk mengharapkan optimasi aktif.

TamaMcGlinn
sumber
1
Kreatif. Namun tampaknya (tidak dikonfirmasi) ini akan diperlakukan sebagai format string dan mungkin atau mungkin tidak dioptimalkan. Di sisi lain pendekatan "+" oleh OP adalah yang terbaik. Menurut spek optimisasi dijamin: stackoverflow.com/a/288802/9399618
Meow Cat 2012
4

Tambahkan beberapa baris: gunakan @

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

Tambahkan Nilai String ke tengah: gunakan $

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

Beberapa string baris Tambahkan Nilai ke tengah: gunakan $ @

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

Jika Anda tidak ingin spasi / baris baru, penambahan string tampaknya berfungsi:

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.

Anda dapat menjalankan di atas di sini jika mau.

rattray
sumber
2
Salah satu (cacat yang ditunjukkan secara tidak sengaja) dengan pendekatan ini adalah bahwa Anda harus sangat berhati-hati untuk memasukkan ruang di mana Anda menginginkannya. Saya akan merekomendasikan pendekatan yang lebih konsisten daripada yang saya ambil (misalnya; selalu di awal baris).
rattray
string + string adalah apa yang OP mulai dengan.
TamaMcGlinn
1

Saya tahu saya agak terlambat ke pesta tetapi saya ingin merekomendasikan https://www.buildmystring.com/ untuk pembaca masa depan utas ini. Anda dapat mengonversi kode apa pun menjadi string C # literal menggunakan situs ini.

aadi1295
sumber
-10

Anda dapat menggunakan dua metode ini:

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

Di SplitLineToMultiline (), Anda perlu menentukan string yang ingin Anda gunakan dan panjang baris, itu sangat sederhana. Terima kasih .

nassimlouchani
sumber