C#中标识符的@前缀是什么意思?

29
"@"字符可以作为前缀,使关键字可用作标识符。 大多数 .net 开发人员知道这一点。 但我们可能不知道的是: 如果两个标识符在去除 "@" 前缀后完全相同,则它们被视为相同。 因此,
static void Main(string[] args)
{
    int x = 123;
    Console.WriteLine(@x);
}

这是绝对有效的代码,并将123打印到控制台。

我很好奇为什么规范中有这样的规则,以及这个特性在现实世界中可能如何使用(如果它们不是关键字,用"@"前缀标识符就没有意义,对吧?)。


1
哦,你的问题是关于为什么@x是有效的。抱歉我一开始没有理解你的问题。对于测试,你也可以打印nameof(@x),你会看到它打印出了x - M.kazem Akhgary
5个回答

41

这是完全合乎逻辑的。 @ 不是名称的一部分,而是一个特殊指示符号,用于将其后面的内容视为标识符而非关键字。


1
这是唯一直接回答问题的答案: "@"不是标识符的一部分,它只用于"转义"标识符的其他部分。 - sleblanc
3
换句话说,这是一个强制性的符号,但作为一种特殊情况,如果名称明确是标识符,则可以省略这个符号。 - Kevin

18

Eric Lippert写了一篇非常好的关于它的文章:Verbatim Identifier

有时候我被问到为什么任何标识符都可以成为保留标识符。为什么不将保留标识符限制在保留和上下文关键字中呢?

答案很简单。想象一下,我们回到当年C#2.0刚推出的时期。你有一个使用"yield"作为标识符的C#1.0程序,这是完全合理的;“yield”在许多商业和科学应用程序中都是一个常见术语。现在,C#2.0被精心设计,以便使用“yield”作为标识符的C#1.0程序仍然是合法的C#2.0程序;只有当它出现在return之前时才具有其特殊含义,并且这在C#1.0程序中从未发生过。但是,你决定将程序中yield的用法标记为保留标识符,以便未来的读者更清楚地知道它是作为标识符而不是作为迭代器的一部分使用的。


14
考虑一个生成 C# 代码的程序示例 -- 例如,它可以使用数据库表中的列创建可比较的 C# POCO 对象,每个列对应一个属性。
如果其中一个列名与 C# 关键字匹配怎么办?如果所有的属性名称都以 @ 为前缀,则代码生成器不必记住哪些单词是关键字。
这是一种保险措施。额外的 @ 字符对代码没有任何影响!

我认为这是正确的方向,有一些通用情况可能会在使用关键字时无法预测。T4模板就是一个很好的例子。 - mikus

7
其他答案已经很清楚地解释了为什么会出现这种行为,但是我认为值得看一下哪些标识符被视为相等的规则。引用规范第2.4.2节:
“如果两个标识符在按顺序应用以下转换后相同,则认为它们是相同的:”
  • 如果使用了前缀“@”,则删除
  • 将每个unicode-escape-sequence转换为其对应的Unicode字符。
  • 删除任何formatting-characters
按照这些规则,@xx是相同的。

3
我认为这个答案并不是很有帮助。原帖的作者想知道为什么规范中会出现这样的内容,他已经知道 @xx 是相同的。 - Matthew Sainsbury
@MatthewSainsbury - 已经有其他三个答案解释了为什么该功能存在。这是为了补充那些答案,以添加有关比较标识符规则的信息。我添加了一些文本以进行澄清。 - theB

4

它提供了确定性:

  • 使用@word是具备未来兼容的。如果它在将来成为一个关键词,就不需要进行任何更改。
  • 大多数程序员可能不熟悉每个关键字(C#有近100个关键字)。
  • 最近的一些关键字是“上下文相关”的,因此有时它们不是关键字。

1
顺带一提,C# 目前恰好有 100 个关键字(其中许多是上下文相关的)。不过在6.0版本中添加 nameof 将使其达到101个。 - Darrel Hoffman
counted103 - 有一些在微软页面上没有提到,例如“by”。 - user1023602
哦,真的吗?我的派对/面试诀窍——能够按字母顺序列出所有关键字(到目前为止已经用4种语言了),可能需要更新一下了……(我去参加一些奇怪的聚会……) - Darrel Hoffman

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