C#多行插值字符串字面量

133

C# 6 带来了对插值字符串字面量的编译器支持,其语法为:

var person = new { Name = "Bob" };

string s = $"Hello, {person.Name}.";

这对于短字符串很好用,但如果你想生成一个较长的字符串,它必须在一行上指定吗?

对于其他类型的字符串,您可以:

    var multi1 = string.Format(@"Height: {0}
Width: {1}
Background: {2}",
        height,
        width,
        background);
或者:
var multi2 = string.Format(
    "Height: {1}{0}" +
    "Width: {2}{0}" +
    "Background: {3}",
    Environment.NewLine,
    height,
    width,
    background);

我无法通过字符串插值找到一种方法,使其不必将整个代码都写在同一行上:

var multi3 = $"Height: {height}{Environment.NewLine}Width: {width}{Environment.NewLine}Background: {background}";

我意识到在这种情况下,可以使用\r\n替换Environment.NewLine(不太便携),或将其提取到本地变量中,但有些情况下,如果不超过一行,则无法减少语义强度。

是否简单的认为对于长字符串,不应使用字符串插值?

对于更长的字符串,我们应该只使用StringBuilder吗?

var multi4 = new StringBuilder()
    .AppendFormat("Width: {0}", width).AppendLine()
    .AppendFormat("Height: {0}", height).AppendLine()
    .AppendFormat("Background: {0}", background).AppendLine()
    .ToString();

还有更优雅的方式吗?


7
https://dev59.com/RlwZ5IYBdhLWcg3wLdoF - Ric
@DmytroShevchenko,我确实考虑过这样做。但是,当我看到你复制/粘贴了Ric发布的链接中的最高票答案,然后编辑它使其看起来不同,我并不确定是否应该接受你的回答。所有这些都发生在5分钟内,所以编辑内容是看不见的。你的回答在技术上是正确的,但我觉得你应该给予信用。我实际上想接受Ric的评论,但这是不可能的。 - Drew Noakes
@DrewNoakes,您的问题已被标记为Ric链接的重复问题。Ric也是标记它的人。因此,在我的答案中不需要再添加该链接的另一个实例。如果您不同意,请让我知道您的理由。当然,我编辑了我的答案中的代码。尽管原因不是为了使其看起来不同,而是为了与您的问题中的示例相匹配。 - Dmytro Shevchenko
@DmytroShevchenko 请查看网站页脚:用户贡献基于CC BY-SA 3.0许可,需要署名。 - Drew Noakes
@DrewNoakes 哈!那是一个很好的论点!:) 我编辑了我的答案。 - Dmytro Shevchenko
3
投票要求重新开启。所谓的重复问题询问的是不同且相反的内容(他们想要源代码中的换行符,但不包括字符串)。版主们在关闭问题之前,请仔细阅读问题! - Colonel Panic
4个回答

273

9
我曾经尝试将它们(可能是两个事物)组合在一起,但是反向尝试没有成功,所以我认为它们不能够结合。并没有想到尝试另一种方式。 - kencordero
9
从C# 8.0开始,您可以按任意顺序使用$和@标记:$@"..."和@$"..."都是有效的插值逐字字符串。在早期的C#版本中,$标记必须出现在@标记之前。 - hal9000
令人惊讶的是,如果字符串中存在转义字符,例如:<?xml version=\"1.0\" encoding=\"UTF - 8\"?>,那么这种方法将无法正常工作。 - dpant
一种解决方法是将字符定义为 char c = '"', 然后执行 $@"<?xml version={c}1.0{c} encoding={c}UTF - 8{c}?>" - Vinod Srivastav

14
自从C#11开始,你可以像这样做(文件multiline.cs):
using System;
public class Program
{
    public static void Main()
    {
        var multiLineStr =
            $$"""
            {
                "Color" : "Blue",
                "Thickness" : {{1 + 1}}
            }
            """;
        Console.WriteLine(multiLineStr);
    }
}

现在字符串变量multiLineStr包含:

{
    "Color" : "Blue",
    "Thickness" : 2
}

说明:

  • 字符串现在由"""分隔,并且内插由{{}}分隔,因为指定了两个连续的$(如果需要,您可以添加更多的$",但对于引号,必须使用相同数量的开放和关闭引号)。

  • 定义起始和结束引号的行缩进很重要! 如果使用不同数量的制表符和/或空格进行缩进,则编译器可能会发出警告。

  • 如果需要,您可以拥有多达3个以上的引号,例如"""""。 请注意,开放和关闭引号的数量必须匹配(在此情况下,需要5个开放和5个关闭双引号来包含字符串)。

  • 使用此新语法,不需要@前缀,因为您不再需要在字符串内部转义双引号

这大大简化了声明多行字符串的过程。

您可以在 Microsoft 中找到完整文档。


注意:您可以在 LinqPad 7 (在首选项- >查询选项卡中,请确保启用了“启用C#/F#预览功能”),在 Visual Studio 或在命令行上尝试它。DotNetFiddle尚不支持新语法。 要在命令行上尝试它,请使用CompileCS批处理文件,您可以在链接中找到它,并像这样调用它:compilecs /run multiline.cs(前提是您已经安装了最新版本的Roslyn)。


我修复了方法以匹配您提供的输出。我想这是一个复制粘贴缩进错误。非静态的 MainDump 方法是 LinqPad 特定的吗?我将其调整为“通常”的 C# 代码,这种情况下可以删除 LinqPad 的注释。 - Ray
@syroot - 感谢您修复格式。在 LinqPad 中,您只需编写 void Main() { ... }。而 .Dump(Title) 是一个扩展方法,您可以将其附加到任何变量或表达式上。它会将对象打印到结果窗口中。如果您感兴趣,您可以在这里找到更多关于 LinqPad 扩展的信息。 - Matt
1
注意:您不必使用双美元符号和大括号。单个符号就可以了,除非您需要在字符串内部使用一些 {} - C-F
@C-F 没错,在一般情况下这并不是必须的,但在我给你的例子中是必需的 - 在那里你需要通过写入{{...}}来转义 { ... } - Matt

13

我可能会使用一种组合

var builder = new StringBuilder()
    .AppendLine($"Width: {width}")
    .AppendLine($"Height: {height}")
    .AppendLine($"Background: {background}");

能否请下投票者提供一些见解?我没有发现任何问题,有问题吗? - sara
记录一下,我实际上给你点了赞。在某些情况下,这可能更易读。我唯一能想到的负面影响是它会为垃圾回收创建一些额外的对象。 - Drew Noakes
3
我认为只有在资源非常有限或需要添加成千上万,甚至百万行时,这才是个例外的负面情况。我不特别喜欢使用逐字字符串进行格式化,因为它会使代码文件中文本的布局影响输出的外观。我更喜欢使用stringbuilder,因为它更具表现力。 - sara
我同意verbatim字符串的格式有点丑。在这里,String.Concat也可能是一个选项。 - Drew Noakes
肯定喜欢concat比verbatim更多。StringBuilder的好处是它会为您处理换行符。不过,我可能两个都可以接受。 - sara
显示剩余3条评论

8

个人而言,我只是使用字符串连接添加另一个插值字符串。

例如:

var multi  = $"Height     : {height}{Environment.NewLine}" +
             $"Width      : {width}{Environment.NewLine}" +
             $"Background : {background}";

我发现这种方式更易于格式化和阅读。

与使用$@" "相比,这种方式会增加额外的开销,但只有在最性能关键的应用程序中才会注意到。在内存字符串操作方面,与数据I/O相比,成本极低。在大多数情况下,从数据库中读取单个变量将需要花费数百倍的时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接