if语句后面的variables声明

在另一个论坛上出现了一个问题,我知道如何解决这个问题,但是它揭示了编译器特有的一个特性。 这个人得到的错误是“embedded式语句不能是声明或标记语句”,因为他们在没有括号的if语句之后声明了一个variables。 这不是他们的意图,但他们已经注意到紧随if语句的代码行,这使得variables声明成为事实上的代码行来执行。 无论如何,这就是我的背景。

以下代码是非法的

if (true) int i = 7; 

但是,如果你把它括在括号里,那全是合法的。

 if (true) { int i = 7; } 

这两个代码都不是有用的。 然而第二个是好的。 这个行为的具体解释是什么?

C#语言规范区分了三种types的语句(更多细节参见第8章)。 一般来说,你可以有这些陈述:

  • 标签声明 – 我猜这是针对老式的goto声明
  • 声明 – 声明 – 这将是一个variables声明
  • embedded语句 – 其中包括几乎所有剩余的语句

if语句中,主体必须是embedded语句 ,这就解释了为什么第一个版本的代码不起作用。 if来自规范(第8.7.1节)的语法如下:

if( boolean-expressionembedded语句
if( boolean-expressionembedded-statement else embedded语句

variables声明是声明语句 ,所以它不能出现在主体中。 如果将括号内的声明括起来,你会得到一个声明块,这是一个embedded语句 (所以它可以出现在那个位置)。

如果不包含方括号,则会执行下一行,就像它被括号括起来一样。 由于在这一行中声明一个variables没有什么意义(你永远无法使用它),所以C#编译器不会允许这样做,以防止在不知情的情况下意外执行它(这可能会引入细微的错误)。

这里是Eric Lippert关于C#编译器关于名称parsing的回答的一部分 :

… C#不是“猜测用户的意思”语言…编译器devise大声抱怨,如果最好的匹配是不起作用的东西

所有编译器将允许您编译无用或使用率极低的代码。 开发人员可以使用这种语言创build没有用的构造的方法太多了。 让编译器抓住所有这些只是太多的努力,通常不值得。

第二种情况在第8.0节开头的C#语言规范中直接调用

该示例导致编译时错误,因为if语句需要embedded语句而不是if语句。 如果这个代码是允许的,那么variables我会被声明,但它永远不会被使用。 但请注意,通过将i的声明放在一个块中,该示例是有效的。

示例代码

 void F(bool b) { if (b) int i = 44; } 

添加closures和开放大括号的其他部分,如果帮助我像我已经做了下面,而不是我在做什么之前添加他们;

之前:这导致了错误:

 protected void btnAdd_Click(object sender, EventArgs e) { if (btnAdd.Text == "ADD") { CATEGORY cat = new CATEGORY { NAME = tbxCategory.Text.Trim(), TOTALSALEVALUE = tbxSaleValue.Text.Trim(), PROFIT = tbxProfit.Text.Trim() }; dm.AddCategory(cat, tbxCategory.Text.Trim()); } else // missing brackets - this was causing the error var c = getCategory(); c.NAME = tbxCategory.Text.Trim(); c.TOTALSALEVALUE = tbxSaleValue.Text.Trim(); c.PROFIT = tbxProfit.Text.Trim(); dm.UpdateCategory(c); btnSearchCat_Click(btnSearchCat, e); } 

After:在else分支中添加括号

 protected void btnAdd_Click(object sender, EventArgs e) { if (btnAdd.Text == "ADD") { CATEGORY cat = new CATEGORY { NAME = tbxCategory.Text.Trim(), TOTALSALEVALUE = tbxSaleValue.Text.Trim(), PROFIT = tbxProfit.Text.Trim() }; dm.AddCategory(cat, tbxCategory.Text.Trim()); } else { var c = getCategory(); c.NAME = tbxCategory.Text.Trim(); c.TOTALSALEVALUE = tbxSaleValue.Text.Trim(); c.PROFIT = tbxProfit.Text.Trim(); dm.UpdateCategory(c); } btnSearchCat_Click(btnSearchCat, e); }