【问题标题】:Multiline string literal in C#C# 中的多行字符串文字
【发布时间】:2010-11-09 04:08:54
【问题描述】:

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

这是我现在拥有的:

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

我知道 PHP 有

<<<BLOCK

BLOCK;

C# 有类似的东西吗?

【问题讨论】:

  • 您的示例中没有换行符。你想要它们吗?
  • 没有。出于可见性/代码清洁的原因,我只想要多行。
  • 在这种情况下,逐字字符串包含换行符。如果你愿意,你可以使用@"...".Replace(Environment.NewLine,"")。
  • 您应该考虑将42绑定为参数,特别是如果它来自用户输入,以避免SQL注入。
  • @weiqure:Environment.NewLine 不一定反映字符串中的换行符,因为换行符是在源代码中出现的。因此,即使每一行上的换行符都与目标系统上的 Environment.NewLine 所说的不同,也可以编写代码!

标签: c# string shorthand


【解决方案1】:

您可以在string 前面使用@ 符号来组成verbatim string literal

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

当您使用此方法时,您还 do not have to escape special characters,但 Jon Skeet 的答案中显示的双引号除外。

【讨论】:

  • 无论如何它是一个字符串文字 - 它是一个带有@符号的 verbatim 字符串文字。
  • 如果你的字符串包含双引号("),你可以像这样转义它们:""(那是两个双引号字符)
  • 有没有办法在不创建新行的情况下完成上述操作?我有一段很长的文本,我希望看到它包含在 IDE 中,而不必使用加号(“hi”+“there”)。
  • @noelicus - 不是真的,但你可以使用上面的 weiqure 技术解决这个问题:@"my string".Replace(Environment.NewLine, "")
  • @afsharm 你可以使用 $@"text"
【解决方案2】:

它在 C# 中称为 verbatim string literal,只需将 @ 放在文字前面即可。这不仅允许多行,而且还关闭转义。所以例如你可以这样做:

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

但是,这包括换行符(使用您的源代码中的任何换行符)到字符串中。对于 SQL,这不仅无害,而且可能提高在您看到字符串的任何地方的可读性 - 但在其他地方可能不需要它,在这种情况下,您要么不需要使用多行逐字字符串文字开始,或从结果字符串中删除它们。

唯一的转义是如果你想要一个双引号,你必须添加一个额外的双引号:

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

【讨论】:

  • 这个答案不正确;它引入了 OP 不需要的换行符。
  • @TamaMcGlinn:我会在答案中添加一些内容 - OP 何时写下这个问题并不清楚。
【解决方案3】:

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

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

【讨论】:

  • 酷,我直到现在才知道这个。如果有人感兴趣:$ 东西被称为“插值字符串”,您可以在此处详细了解它:msdn.microsoft.com/en-us/library/dn961160.aspx
  • tx,修正了措辞
  • 我假设字面大括号必须加倍,例如$@"{{example literal text { fooString }. }}" 这可能会让一些人感到困惑,因为 Angular、React 和 Vue.js 使用相反的约定。
  • 这是一个很酷的发现。虽然,如果您的插值字符串值调用方法 - 例如:{date.ToString("yyyy-mm-dd")} 您可能需要考虑@dav_i 答案,因为插值更干净,而不必弄乱双引号
【解决方案4】:

我发现使用字符串文字的问题是它会使你的代码看起来有点“奇怪”,因为为了不让字符串本身出现空格,它必须完全左对齐:

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

呸。

所以我喜欢使用的解决方案是:

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

当然,如果您只是想像现在这样在逻辑上拆分 SQL 语句的行并且实际上不需要新行,您可以随时将 Environment.NewLine 替换为 " "

【讨论】:

  • 干净多了,谢谢。此外,String.Concat 的工作方式类似,不需要分隔符。
  • 虽然丑陋,但第一个版本不需要代码即可运行。第二个选项显然具有连接单独字符串的运行时开销。
  • 谢谢你,但在逐字逐句的情况下,这无济于事。喜欢: [Tooltip(@"Very long string.....")] 您无法运行任何代码。我打算逐字记录,因为当我使用全屏编辑器时,代码作为单行字符串参数看起来很难看。但是随后逐字将其他不可见字符添加到字符串本身,所以我找不到任何其他方式。
  • 虽然编译正常,而且看起来更好,但它未能通过代码验证,因为它容易受到 SQL 注入攻击。不允许在运行时构造任何查询字符串。它必须是一个常数。
  • 我也喜欢这种方法,因为它使插值更清晰。想象一下,如果你想做类似"The", "Quick", $"{fox.color}", "Fox"
【解决方案5】:

另一个需要注意的问题是在 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)

【讨论】:

  • 它有什么不同?有或没有“@”你必须加倍“{{”才能得到“{”作为可打印字符,这是String.Format的问题,而不是字符串内容。
  • 对于想要将 Javascript 代码放在字符串中的人来说,这是一个值得注意的问题,这可能比常规字符串更常见的是逐字字符串文字。
  • 在新的 C# 6.0 中,您可以将索引属性运算符与逐字字符串文字一起使用(如 $@"Value is {this.Value}";)
  • @Heliac 我认为您的意思是插值字符串也可以是该语法的文字。 var query = $@" select foo, bar from table where id = {id} ";
【解决方案6】:

为什么人们总是将字符串与字符串文字混淆?接受的答案是对不同问题的一个很好的答案;不是这个。

我知道这是一个老话题,但我来到这里可能与 OP 相同的问题,看到人们如何一直误读它令人沮丧。或者我看错了,我不知道。

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

在 C# 中,语句...

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

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

OP 似乎在问什么——至少我会用这些话问什么——不是如何在编译的字符串中引入模仿源代码中的换行符,而是如何为清晰的源代码中的一长串文本在编译的字符串中没有引入中断。并且不需要延长执行时间,就可以将来自源代码的多个子字符串连接起来。就像 javascript 或 C++ 中多行字符串文字中的尾部反斜杠一样。

建议使用逐字字符串,不要介意StringBuilders,String.Joins 甚至是带有字符串反转的嵌套函数等等,这让我觉得人们并没有真正理解这个问题。或者我不明白。

据我所知,C# 没有(至少在我仍在使用的旧石器时代版本中,从前十年开始)具有干净地生成多行字符串 literals 的功能,可以在编译而不是执行。

也许当前版本确实支持它,但我想我会分享一下我所感知的字符串和字符串文字之间的区别。

更新:

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

【讨论】:

  • 一些人(包括我自己)在查看原始问题时可能会感到困惑的是,here-doc 格式(shell、php、perl、...)包括换行符。因此,如果 OP 与 PHP 的 heredoc 进行比较,那么包含换行符应该不是问题。
  • 没错。据我所知,您的回答“不,您不能在 C# 中执行此操作”是正确的。
  • 有人告诉我,在 Java 中,这样的连接字符串将在编译后的字节码中变成单个字符串文字。也许 dot Net 也这样做?
  • 你可以。 OP 的“+”方法是最好的。根据规范保证优化:stackoverflow.com/a/288802/9399618 仍然是少数理解这个问题的人之一。是否可以删除或折叠可能具有误导性但已被接受的答案?
  • 感谢您的提示,@MeowCat2012。看一些反编译的代码,好像确实是这样。
【解决方案7】:

添加多行:使用@

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

【讨论】:

    【解决方案8】:

    您可以使用 @""

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

    【讨论】:

    • 你应该解释每一个的作用,因为@是逐字字符串,""是转义双引号。
    • 是否有一种快速的方法可以做到这一点,而无需查找/替换所有双引号,例如粘贴的 JSON?
    【解决方案9】:

    我还没有看到这个,所以我会把它贴在这里(如果你有兴趣传递一个字符串,你也可以这样做。)这个想法是你可以将字符串分成多行并添加你自己的以您希望的任何方式显示内容(也可以在多行上)。这里“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
                                    )";
        }
    

    【讨论】:

    • 我会说非常危险:有人很容易以这种方式进行 sql 注入。
    • 只要您知道查询字符串中的所有变量(如果有的话!)都来自代码常量或其他安全来源 - 例如,createTable("MyTable"); 无论如何,OP 的问题是关于如何直接在代码中输入多行字符串文字,而不是如何构建数据库查询本身。 :)
    • 应该可能使用字符串生成器,尤其是在加号 (+) 的数量很多的情况下。
    【解决方案10】:

    是的,您可以将一个字符串拆分为多行,而无需在实际字符串中引入换行符,但它并不漂亮:

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

    诀窍是引入计算结果为空的代码,并且该代码可以包含换行符而不影响输出。我将这种方法从 this answer 调整为类似的问题。

    对于问题是什么,显然有些混淆,但有两个提示,我们想要的是一个不包含任何换行符的字符串文字,其定义跨越多行。 (在他这么说的 cmets 中,“这就是我所拥有的”显示了不会创建带有换行符的字符串的代码)

    这个单元测试显示了意图:

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

    更改上述查询的定义,使其成为一个字符串文字,而不是两个字符串文字的连接,编译器可能会或可能不会优化为一个。

    C++ 方法是用反斜杠结束每一行,导致换行符被转义,并且不会出现在输出中。不幸的是,仍然存在这样的问题,即第一行之后的每一行都必须左对齐,以免在结果中添加额外的空格。

    只有一个选项不依赖可能不会发生的编译器优化,那就是将您的定义放在一行上。如果你想依赖编译器优化,你已经拥有的 + 很棒;您不必左对齐字符串,结果中不会出现换行符,而且它只是一个操作,没有函数调用,可以期待优化。

    【讨论】:

    • 创意。但是,似乎(未确认)这将被视为格式字符串,可能会或可能不会被优化。另一方面,OP 的“+”方法是最好的。根据规范保证优化:stackoverflow.com/a/288802/9399618
    【解决方案11】:

    如果您不想要空格/换行符,字符串添加似乎可以工作:

    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.
    

    如果你愿意,你可以运行上面的here

    【讨论】:

    • 这种方法的一个(无意中证明)缺陷是您必须非常小心地将空格包含在您想要的位置。我会推荐一种比我采取的更一致的方法(例如;总是在行首)。
    • string + string 正是 OP 的开头。
    猜你喜欢
    • 2010-11-11
    • 2016-01-19
    • 2011-02-27
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-14
    相关资源
    最近更新 更多