字符串插值 - 大括号内的@符号是什么意思?

23

考虑:

string newline = "\r\n";

Console.WriteLine($"Hello without at{newline}how are you?");
Console.WriteLine($"Hello with at{@newline}how are you?");

这两行代码的输出结果是相同的。换行符总是被打印成一个新的一行。

Hello without at
how are you?
Hello with at
how are you?

那么我何时需要在大括号中使用“@”符号


1
可能是重复的问题:https://dev59.com/uW025IYBdhLWcg3wOzTY - Keyur Ramoliya
5
这个跟问题相关。 - Mong Zhu
7
这绝对不是与那个重复的。那是关于逐字字符串文字。这不是其中之一。它是使用带有标识符@,通常与关键字一起使用,例如在扩展方法中将@this作为第一个参数的名称。 - Jon Skeet
@KeyurRamoliya:并不是重复的问题,因为那不是字符串字面量,而是一个变量。有趣且新奇的是,这个变量本身不需要带有 @,但你可以使用带或不带 @ 的这个变量。 - Tim Schmelter
另一个相关的线程是@ prefix for identifiers in C# - Jeppe Stig Nielsen
显示剩余2条评论
2个回答

30

$"Hello { myValue }"是在C#6中引入的插值字符串,这等同于调用String.Format("Hello {0}", myValue)

当您的变量与关键字具有相同的名称时,需要使用保留符号(@),但据我所知,newline不是关键字。但以下内容会导致编译器错误:

String.Format("Hello {0}", if)

虽然这不会:

String.Format("Hello {0}", @if)

这里的verbatim告诉编译器,if是一个变量名,不是if关键字。

所以在您的情况下,您不需要verbatim,因为newline不是关键字。换句话说,您的代码等效于以下代码:

Console.WriteLine("Hello with at{0}how are you?", @newline);

这是一种有效的(尽管多余的)verbatim使用方式。

有关字符串插值的更多信息,请参阅有关字符串插值的文档


2
$ is not really a shortcut for String.Format it basically returns a FormattableString which in many ways differs from String.Format - mrogal.ski
1
$"Hello {myValue}"实际上也是string.Format的一种快捷方式,因为编译器只有在表达式的唯一目标是FormattableString时才会使用它。所以编译器会直接将其重新格式化为一个string.Format调用。 - Lasse V. Karlsen
2
这个答案基本上是正确的,但它有一点夸张。@并不表示“这是一个变量的名称”,因为该名称可能无法解析为“变量”。它可能会解析为常量、方法、属性、类、结构体、类型参数或事件,这些都不是“变量”。相反,它表示这个“标识符”不应被视为关键字。 - Eric Lippert
1
@EricLippert 在第一种情况下,如果它不能很好地维护以跟上罕见的关键字添加,那么您也不想使用它;它几乎肯定会遭受其他长期存在的问题。因此,它仍然只是促进垃圾使用。在第二种情况下,他们应该在生成之前验证输入。这将使代码库未来兼容任何新的关键字添加。除此之外,他们必须普遍地在每个标识符上放置@才能帮助未来证明。否则,它无论如何都会随着更新而中断。 - jpmc26
1
值得一提的是不同编程语言之间的互操作性。一个语言中的关键字不一定是第二个语言中的关键字。 - Karol
显示剩余19条评论

15

这是一个冗余的逐字前缀。根据C#规范

前缀“@”允许使用关键字作为标识符,这在与其他编程语言进行交互时非常有用。字符“@”实际上并不是标识符的一部分,因此该标识符在其他语言中可能被视为普通标识符,而无需前缀。带有“@”前缀的标识符称为逐字标识符。允许对非关键字标识符使用“@”前缀,但出于样式考虑,强烈不建议这样做。

如果您想编写这样一个函数,则可以使用逐字标识符:

private void print(string @string) => Console.WriteLine(@string);

通常情况下,你不能将标识符命名为string,因为它是一个保留关键字。但使用@前缀可以实现。


4
重要的部分是“字符@实际上不是标识符的一部分”,因为它解释了即使变量没有它,它为什么会编译。 - Tim Schmelter
4
我认为另一个重要的部分是:“允许对非关键字标识符使用@前缀,但在风格上强烈不建议这样做。”因此,@newline虽然被容许,但会产生误导和混淆。 - Jeppe Stig Nielsen
我注意到你的示例与你从规范中引用的文本不匹配,这是一个非常糟糕的用例。该功能的目的不是让您创建一个名为@string形式参数,因为那将是一件奇怪的事情。该功能的目的是允许您扩展使用非C#语言编写的第三方类,该类具有名为string的虚成员。您需要能够说class D:ThirdParty {public override void @string(){...}}。这将是一个按设计使用案例。 - Eric Lippert
@EricLippert 这可能很奇怪,但人们用它来做这个例子。(刚刚偶然发现) - ChristianMurschall
虽然我同意这是一个使用案例,但它不是一个“激励”案例。也就是说,如果该特性不存在,我们不会将此场景作为创造该特性的动机。任何使用@this的人都可以轻松地使用_this,因此没有令人信服的好处。 - Eric Lippert
显然,自从v3版本添加了扩展方法,那绝对不是一个激励人心的情景。 - Eric Lippert

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