C#中字符串前面的@符号是什么意思?

753

这是一个.NET问题,涉及C#(或可能是VB.net),但我正在尝试弄清楚以下声明之间的区别:

string hello = "hello";

对比。

string hello_alias = @"hello";

在控制台上打印输出对长度属性没有影响。


请查看(并点赞)我为Visual Studio IDE提出的更好的逐字字符串格式化建议:缩进多行逐字字符串 - Olivier Jacot-Descombes
要明确的是,上面的例子使用@或不使用@都会产生完全相同的结果。 - Miro J.
9个回答

955

它将字符串标记为逐字字符串字面值 - 字符串中任何通常被解释为转义序列的内容都会被忽略。

所以"C:\\Users\\Rich"@"C:\Users\Rich"是相同的。

但有一个例外:如果需要转义双引号,则需要使用转义序列。要转义双引号,需连续放置两个双引号。@"""" 例如将求值为 "


1
@RichardEverett 我理解了答案,但我的疑问是这个功能的实际用途是什么? - Arun
40
处理包含像正则表达式定义之类的需要转义的内容时,这非常有用。@Arun - James Thorpe
34
请将以下英文文本翻译成中文:
  • 多行内容
- Jaider
6
如果您想在string.Format调用中使用普通大括号,则仍需要将大括号 {{ 加倍。 - Dave Cousineau
5
@RichardEverett 这个功能非常有用,可以创建多行字符串文字,而不必将文本分成若干部分。 - John Mott
显示剩余4条评论

301

这是一个原样字符串字面量。这意味着转义字符不会被应用。例如:

string verbatim = @"foo\bar";
string regular = "foo\\bar";

这里verbatimregular具有相同的内容。

它还允许多行内容-这对于SQL非常方便:

string select = @"
SELECT Foo
FROM Bar
WHERE Name='Baz'";

对于原样字符串字面量来说,唯一需要转义的就是双引号("),可以通过把它重复两次来实现:

string verbatim = @"He said, ""Would you like some coffee?"" and left.";
string regular = "He said, \"Would you like some coffee?\" and left.";

19
它还允许使用保留字作为变量名等内容。例如:public int GetValueOrDefault(int @default); - Svish
7
Svish:确实如此,但与此特定问题无关。 - Jon Skeet

75

'@'还有另外一个含义:在变量声明前面加上它可以让你使用保留关键字作为变量名。

例如:

string @class = "something";
int @object = 1;

我只发现了一两个合法的用途。主要是在ASP.NET MVC中,当您想要执行以下操作时:

<%= Html.ActionLink("Text", "Action", "Controller", null, new { @class = "some_css_class" })%>

这将生成一个类似于HTML链接的东西:

<a href="/Controller/Action" class="some_css_class">Text</a>
否则,你将不得不使用“Class”,它不是保留关键字,但大写的“C”不遵循HTML标准,看起来也不对。

19

既然你明确要求包括VB,那么让我补充一下,这种逐字字符串语法在VB中并不存在,只存在于C#中。相反,在VB中所有字符串都是逐字的(除了它们不能包含换行符,不像C#的逐字字符串):

Dim path = "C:\My\Path"
Dim message = "She said, ""Hello, beautiful world."""

在 VB 中不存在转义序列(除了像 C# 中的逐字字符串中引号字符的加倍),这使得一些事情更加复杂。例如,要在 VB 中编写以下代码,您需要使用连接(或任何其他构造字符串的方法)。

string x = "Foo\nbar";

在VB中,这将被编写为:

Dim x = "Foo" & Environment.NewLine & "bar"

&是VB中的字符串连接运算符,+同样可以使用。


2
哦,那听起来很烦人......更高兴我现在在使用C# :p - Svish
@Svish,等等,我有什么遗漏吗?这并不是VB的缺点。事实上,这是VB胜过C#的一个方面。最好以这种方式进行,并显式地连接换行符和特殊字符,而不是将所有特殊字符放在“”之间。 - Pacerier
@Pacerier 那是无稽之谈。一旦你进行的不仅仅是琐碎的字符串处理,适当的字符串构建工具就是必不可少的,而简洁地处理特殊字符的能力则是其中最重要的。然而,C#和VB都有String.Format,可以做到这一点。事实上,我现在永远不会"x" & Environment.NewLine,而是总是使用String.Format("x{0}", Environment.Newline)等等。尽管如此,在这方面C#更加方便。 - Konrad Rudolph
@KonradRudolph,我会选择 "x" & nl & nl 或者 "x" + nl + nl 或者 "x" . $nl . $nl 每天都胜过于 "x\n\n"。同时 "x" + bs + bs 胜过于 "x\\\\"。还有 "x" + q + q 胜过于 "x\"\"" / "x"""""。现在关于 String.Format,那完全是另一个问题,并且与上面的比较无关。 - Pacerier
@Pacerier 你能说出为什么吗?它更长,而且肯定不会更清晰 - 两者都需要适应。 - Konrad Rudolph
显示剩余4条评论

12

http://msdn.microsoft.com/en-us/library/aa691090.aspx

C#支持两种形式的字符串字面量:常规字符串字面量和逐字字符串字面量。

常规字符串字面量由双引号括起来的零个或多个字符组成,例如"hello",可以包含简单的转义序列(如制表符字符\t)以及十六进制和Unicode转义序列。

逐字字符串字面量由@字符后跟双引号字符、零个或多个字符和一个闭合双引号字符组成。一个简单的例子是@"hello"。在逐字字符串字面量中,定界符之间的字符被逐字解释,唯一的例外是引号转义序列。特别地,简单的转义序列和十六进制和Unicode转义序列不会在逐字字符串字面量中处理。逐字字符串字面量可以跨越多行。


11

这是一个原样字符串,它改变了转义规则 - 现在仅有的转义字符是双引号 ",被转义为 ""。 这对于文件路径和正则表达式特别有用:

var path = @"c:\some\location";
var tsql = @"SELECT *
            FROM FOO
            WHERE Bar = 1";
var escaped = @"a "" b";

等等


马克,你的示例中不是缺少了@符号吗?还是当我使用var时它是默认的?有点困惑... - Dirk Vollmar
1
好的 - 这真的非常奇怪。我想知道是不是编辑器把它们弄乱了? - Marc Gravell

9
在字符串前面加上@符号,可以让你使用特殊字符,比如反斜杠或双引号,而无需使用特殊代码或转义字符。
因此,你可以这样写:
string path = @"C:\My path\";

替代方案:

string path = "C:\\My path\\";

9

MSDN复制:

在编译时,逐字字符串将转换为带有相同转义序列的普通字符串。因此,如果在调试器监视窗口中查看逐字字符串,则会看到编译器添加的转义字符,而不是源代码中的逐字版本。例如,逐字字符串@"C:\files.txt"在监视窗口中显示为"C:\\files.txt"


在我看来,这是微软文档中典型的误导性内容!上述内容所述的结果是正确的,但其基本真相是C#中的字符串被转换为相关的字节序列(或多字节字符代码)。C#允许使用@"..."或"..."两种不同的方式表示底层字符串。调试器总是选择"..."方式,并且无法确定最初使用了哪种方式。(诸如\n或""之类的转义序列仅与编程和显示级别的字符串表示有关,从不存储在底层字符串中!) - MikeBeaton

3
解释很简单。为了表示字符串"string\",编译器需要使用"string\\",因为\是转义字符。如果您使用@"string\",则可以忘记\\

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