ChatGPT解决这个技术问题 Extra ChatGPT

C# 中的多行字符串文字

有没有一种简单的方法可以在 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 所说的不同!

M
Max Yankov

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

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

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


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

它在 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 何时编写问题尚不清楚。
R
Riegardt Steyn

附带说明一下,在 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 答案,因为插值更干净,而不必弄乱双引号
d
dav_i

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

    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" 的事情
M
Martin Clarke

另一个需要注意的问题是在 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} ";
C
Carvo Loco

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

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

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

在 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


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

添加多行:使用@

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

v
vovkas

您可以使用@ 和“”。

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

您应该解释每个的作用,因为 @ 用于逐字字符串,而 "" 用于转义双引号。
有没有一种快速的方法来做到这一点而无需查找/替换所有双引号,例如粘贴的 JSON?
R
RobertHana

我还没有看到这个,所以我会把它贴在这里(如果你有兴趣传递一个字符串,你也可以这样做。)这个想法是你可以将字符串分成多行并添加你自己的内容(也在多行上)以您希望的任何方式。这里“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 的问题是关于如何输入多行字符串文字直接在代码中,而不是如何构建数据库查询本身。 :)
应该可能使用字符串生成器,特别是如果加号 (+) 的数量很多。
T
TamaMcGlinn

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

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

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

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

此单元测试显示了意图:

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

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

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

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


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

如果您不想要空格/换行符,则字符串添加似乎有效:

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


这种方法的一个(无意中展示的)缺陷是您必须非常小心地将空格包含在您想要的位置。我会推荐一种比我采取的更一致的方法(例如;总是在行的开头)。
不过,字符串 + 字符串正是 OP 的开头。
K
Kind Contributor

在 C# 11 [2022] 中,您将能够使用原始字符串文字。使用原始字符串文字可以更轻松地使用 " 字符,而无需编写转义序列。

OP的解决方案:

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

string query2 = """
    SELECT foo, bar
    FROM table
    WHERE id = 42
    and name = 'zoo'
    and type = 'oversized "jumbo" grand'
    """;

有关原始字符串文字的更多详细信息

有关完整详细信息,请参阅 Raw String Literals GitHub 问题;和Blog article C# 11 Preview Updates – Raw string literals, UTF-8 and more!