为什么在任何成员变量(即调用函数/属性)之前允许'@'不影响其值?

时间:2013-06-04 13:54:28

标签: c# asp.net

我知道'@'关键字在C#中用于不同目的,如所讨论的here,但我的问题不同。

假设我使用@ConfigurationManager.AppSetting["DbConnectionString"]代替ConfigurationManager.AppSetting["DbConnectionString"]。它仍然以同样的方式工作。

所以我的问题是:

  1. 为什么编译器在不影响其值的情况下允许使用'@'符号?
  2. 如上所述,'@'符号可以改变任何场景中的值吗?
  3. 为了更清楚,我想再添加一个例子:

    假设我有一个具有静态函数的类'ConfigurationLoader' 'GetConfigurations'返回一个字符串列表。

    然后,我可以将其称为List<string> ConnectionStrs=ConfigurationLoader.GetConfigurations();

    如果我将其设为List<string> ConnectionStrs=@ConfigurationLoader.GetConfigurations();,那么它仍然会给出相同的结果。在这样的场景中,我问上面两个问题。

4 个答案:

答案 0 :(得分:24)

更新:这个问题是the subject of my blog in September 2013。谢谢你提出的好问题!


  

如上所述,'@'符号可以改变任何场景中的值吗?

没有

  

我们正在讨论的功能是什么?

在C#中,如果您在@前加上任何标识符,则标识符允许但不必需作为关键字。此功能允许开发人员使用保留关键字作为标识符:

static void M(bool @unsafe) { ... }

它允许您强调可能与上下文关键字混淆的标识符实际上是一个标识符:

@yield = 123.45;

如果没有@,这将是合法的,但它清楚地表明开发人员在这里并不是yield return 123.45;

  

那么为什么允许使用不是关键字的标识符?

让我们进入回归机器,回到C#2.0的世界。我们假设该功能与您的建议方式相同:@只能 继续保留和上下文关键字。你用C#2.0编写这个程序:

class P
{
  static void Main()
  {
    int @yield = 123;
  }
}

这是一个合法的 C#2.0 程序似乎有点奇怪但不是合法的C#1.0程序尽管不使用C#2.0的功能吗?

设计的功能允许您在使用不同版本的C#的两个团队之间共享代码。它允许你在团队中一个人试用C#2.0,看看它是否有效,而其他人仍在使用C#1.0。您提出的功能会使这两种情况变得噩梦,并​​为采用新版本的语言带来了障碍。升级已经足够昂贵了;语言设计团队不想让它变得更加昂贵。

设计的功能还可以实现“面向未来”。假设您正在编写生成其他程序的程序。您也可以使用@将生成的程序前言所有标识为{{1}},因为您不知道哪些单词将成为 future 版本C#中的关键字。

  

我在哪里可以阅读有关C#的关键字规则的更多信息?

http://ericlippert.com/2009/05/11/reserved-and-contextual-keywords/

答案 1 :(得分:6)

正如你可以从大量评论中看出的那样,你的问题并没有真正令人满意的答案。不过我会尝试一下:

<强> 1。为什么编译器在不影响其值的情况下允许使用'@'符号?

因为这就是语言规范所说的。令牌之前的@符号并不意味着“下一个令牌是关键字,但将其视为标识符”。这不是规范的编写方式,因此不是语言编译器的工作方式。相反,它意味着“无论下一个标记是什么,将其视为标识符,即使恰好是关键字”。

就像说“假装蓝色是一种颜色”一样。这很容易做到,因为蓝色一种颜色。类似地,说“假装myCollection不是C#关键字”很容易 - 它不是 C#关键字,所以没什么可做的。

我怀疑,你真正想要问的是:

<强> 1b中。为什么设计C#的人以这种方式定义@符号的行为?

这个问题,我担心,只有帮助定义C#的人才能回答。我们可以猜测,答案肯定会是几个人已经评论过的答案:因为这种方式更容易(解释,记录,实施,测试等)并且没有任何缺点。好吧,除了一些开发人员的一些轻微的混乱。 :)

在规范中添加一个要求,即编译器在“滥用”@符号时执行某些操作意味着需要做很多工作。你必须定义它的作用(它是一个警告吗?错误?),你必须在规范中添加正确,准确,校对,明确的语言,你必须将代码添加到编译器中以产生新的行为,你必须记录新的行为,你必须编写测试脚本来行使新的行为,等等。所有这些都是一个没有额外好处的“功能”。

它确实使用了@ redundant,但是由于各种原因,C#允许你做很多冗余的事情。您可以添加冗余(),您可以添加冗余的委托构造函数,您可以添加冗余的可访问性关键字。而且,正如您所看到的,如果您愿意,可以在所有地方添加多余的@

<强> 2。 “@”符号可以更改上述任何场景中的值吗?

这一个,我们可以回答:不。如果你将@放在已经是标识符的标记之前,它将被视为标识符 - 无论如何编译器将要引用的完全相同的标识符。你不会看到任何行为上的变化,只是额外输入。

答案 2 :(得分:0)

您引用的问题可以回答您的问题。在此上下文中,@告诉编译器下一个符号是标识符,没有关键字。您ConfigurationManager不需要它,但它仍然可以使用。以下是需要它的示例:

class @class
{
    public @class()
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        @class c = new @class();
    }
}

答案 3 :(得分:0)

您可以使用@符号将保留关键字用作简单的变量名称,例如:

int @for = 10;

Console.WriteLine(@for); // 10

同样,你可以有一个名为@hello而不是hello的变量,即使hello不是一个需要@前缀的保留关键字将它用作变量名。

编辑,说明未在保留关键字上使用时允许使用的真正原因。

两个可能的原因:

  1. @应该只允许保留关键字(以及转义字符串),但是有人忘了if而其他人不关心。
  2. @应该被允许保留关键字,并且首先没有人关心它是否会以其他方式使用。