C#中的多行字符串文字


1046

有没有一种简单的方法可以在C#中创建多行字符串文字?

这是我现在所拥有的:

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

我知道PHP有

<<<BLOCK

BLOCK;

C#是否有类似的东西?


1
您的示例中没有换行符。你想要他们吗?
weiqure

8
否。出于可见性/代码清洁度的原因,我只需要多行。
切特

6
在这种情况下,逐字字符串包含换行符。如果愿意,可以使用@“ ...”。Replace(Environment.NewLine,“”)。
weiqure

9
您应该考虑将绑定42作为参数,特别是如果它来自用户输入,则应避免将其作为SQL注入。
JensMühlenhoff2013年

@JensMühlenhoff有人将如何注入在代码中定义的硬编码字符串?
男孩先生

Answers:


1587

您可以使用@a前面的符号string形成逐字字符串文字

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

使用此方法时,除了双引号(如Jon Skeet的答案所示)外,您也不必转义特殊字符


43
无论如何,这是一个字符串文字-它是带@符号的逐字字符串。
乔恩·斯基特

95
如果您的字符串包含双引号(“),则可以像这样对它们进行转义:”“(多数民众赞成在两个双引号字符之间)
Muad'Dib

8
有没有一种方法可以完成上述操作而不创建新行?我想看一段很长的文本,而不必使用加号(“ hi” +“ there”)包裹在IDE中。
noelicus

2
@noelicus-并非如此,但是您可以通过使用上述weiqure的技术来解决该问题:@"my string".Replace(Environment.NewLine, "")
John Rasch

8
@afsharm您可以使用$ @“ text”
Patrick McDonald

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
这个答案是不正确的。它引入了OP不需要的换行符。
TamaMcGlinn

@TamaMcGlinn:我将在此问题的答案中添加一些内容-尚不清楚OP何时写下该问题。
乔恩·斯基特

105

我发现使用字符串文字的问题在于,它会使您的代码看起来有些“ 怪异 ”,因为为了不在字符串本身中获得空格,必须将其完全左对齐:

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

uck

因此,我喜欢使用的解决方案使所有内容与其余代码保持一致:

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

当然,如果你只是想在逻辑上分割的SQL语句的线条像你和实际上并不需要一个新的线,你永远可以替代Environment.NewLine" "


2
清洁得多,谢谢。另外,String.Concat的工作原理类似,不需要分隔符。
塞斯

谢谢。我喜欢在String.Join中使用SQL的定界符“”,因为它允许缩进/配对匹配,并且避免了必须添加前导空格。
Rob在TVSeries.com上2015年

7
虽然很丑陋,但第一个版本不需要运行任何代码。第二个选项显然需要运行时开销来连接单独的字符串。
Gone Coding

@GoneCoding,您确定吗?编译器可以优化串联。
William Jockusch '16

@WilliamJockusch:通常,非操作员函数调用(如join)将保持不变,并且不会进行优化。最好检查编译后的代码,但我会花钱打电话优化。
Gone Coding

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 2011年

12
对于想要将Javascript代码放入字符串的人来说,这是一个值得注意的陷阱,与常规字符串相比,使用逐字字符串字面量可以更频繁地完成此操作。
Ed Brannin

2
在新的C#6.0中,您可以将索引属性运算符与逐字字符串文字一起使用(例如$ @“ Value is {this.Value}”;)
Heliac 2015年

2
@Heliac我认为您的意思是,内插字符串也可以使用该语法来表示文字。var query = $ @“从表中选择foo,bar,其中id = {id}”;
brianary

101

附带说明,在C#6.0中,您现在可以将内插字符串与逐字字符串文字结合起来:

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

10
太酷了,直到现在我才知道。如果有人感兴趣:$ thing称为$“ Interpolated Strings”,您可以在此处详细了解:msdn.microsoft.com/zh-cn/library/dn961160.aspx
Hauke P.16年

tx,修正了措辞
Heliac

1
我假设必须将字面大括号加倍,例如,$@"{{example literal text { fooString }. }}" 这可能会造成混淆,因为Angular,React和Vue.js使用相反的约定。
Patrick Szalapski '18

58

人们为什么总是将字符串与字符串文字混淆?公认的答案是对其他问题的很好答案。不是这个。

我知道这是一个古老的话题,但是我来到这里时可能遇到与OP相同的问题,看到人们如何继续误读它令人沮丧。也许我读错了,我不知道。

粗略地说,字符串是计算机内存的区域,在程序执行期间,该字符串包含可映射为文本字符的字节序列。另一方面,字符串文字是一段尚未编译的源代码,它表示以后执行该字符串的程序执行期间用于初始化字符串的值。

在C#中,该语句...

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

... 不会产生三行线,而是产生一根线;三个字符串的串联(每个字符串都从不同的文字初始化),其中三个都不包含换行符。

OP似乎要问的问题-至少我要用这些词问的问题-不是如何在已编译的字符串中引入模仿源代码中所出现的换行符的方式,而是如何为清晰起见而长期分拆,即源代码中的单行文本,而不会在已编译的字符串中引入中断。而且不需要延长执行时间,就可以花一些时间来连接源代码中的多个子字符串。就像javascript或C ++中多行字符串文字中的尾部反斜杠一样。

建议使用逐字字符串,nevermind StringBuilderString.Joins甚至是带有字符串反转的嵌套函数,而不要使用什么,使我认为人们并没有真正理解这个问题。也许我听不懂。

据我所知,C#(至少在我使用的旧石器版本中,至少在过去的十年中)没有干净地产生多行字符串文字的功能,这些文字可以在编译而不是执行期间进行解析。

也许当前的版本确实支持它,但是我想我应该分享我认为字符串和字符串文字之间的区别。

更新:

(来自MeowCat2012的评论)可以。OP的“ +”方法是最好的。根据规范,可以保证优化:http : //stackoverflow.com/a/288802/9399618


1
一些人(包括我自己)可能在看原始问题时感到困惑的是,here-doc格式(shell,php,perl等)包含换行符。因此,如果OP正在与PHP的Heredoc进行比较,那么包括换行符就不应该成为问题。
Tanktalus

究竟。据我所知,您的回答“不,您不能在C#中做到”是正确的。
TamaMcGlinn

有人告诉我,在Java中,这样的连接字符串将成为已编译字节码中的单个字符串文字。也许dot Net也这样做?
喵喵猫2012年

2
您可以。OP的“ +”方法是最好的。根据规范,可以保证优化:stackoverflow.com/a/288802/9399618仍然是少数几个理解问题的人之一。是否可以删除或折叠可能引起误解但被接受的答案?
猫猫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注入。
2014年

4
只要您知道查询字符串中的所有变量(如果有的话!)都来自代码常量或其他安全来源就可以了,例如,createTable("MyTable"); 无论如何,OP的问题是关于如何直接在代码中输入多行字符串文字,而不是如何构造数据库查询本身。:)
dbeachy1

2
应该使用字符串生成器,尤其是当加号(+)数量很多时。
gldraphael 2015年

8

您可以使用@“”

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

2
您应该解释每个函数的含义,因为@表示逐字字符串,而“”表示转义双引号。
AFract

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
这种方法的一个(无意中证明了)缺陷是,您必须非常小心地在需要它们的位置包括空格。我建议使用比我采用的方法更一致的方法(例如,始终在该行的开头)。
拉特雷

字符串+字符串只是OP开始的目的。
TamaMcGlinn


-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()中,您需要定义要使用的字符串和行长,这非常简单。谢谢 。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.