为什么是陈述(j++);被禁止的
本文关键字:禁止 j++ 陈述 为什么 | 更新日期: 2023-09-27 18:27:42
以下代码错误(请参阅ideone):
public class Test
{
public static void Main()
{
int j = 5;
(j++); // if we remove the "(" and ")" then this compiles fine.
}
}
错误CS0201:只有赋值、调用、递增、递减、等待和新的对象表达式可以用作语句
- 当我们去掉括号时,为什么代码会编译
- 为什么它不使用括号编译
- 为什么C#是这样设计的
深刻的见解值得赞赏。
我会尽力的。
正如其他答案所指出的,这里发生的事情是编译器检测到表达式被用作语句。在许多语言中——C、JavaScript和许多其他语言——将表达式用作语句是完全合法的。2 + 2;
在这些语言中是合法的,尽管这是一个无效的声明。有些表达式仅对其值有用,有些表达式只对其副作用有用(例如对void返回方法的调用),不幸的是,有些表达式对两者都有用。(类似增量。)
要点是:只有表达式组成的语句几乎肯定是错误,除非这些表达式通常被认为比它们的值更有用。C#设计者希望找到一个中间立场,允许那些通常被认为是副作用的表达式,而不允许那些通常也被认为对其价值有用的表达式。他们在C#1.0中确定的一组表达式是增量、递减、方法调用、赋值,还有一些有争议的构造函数调用。
ASIDE:人们通常认为对象构造是用于它所产生的价值,而不是用于构造的副作用;在我看来,允许CCD_ 2是一个有点错误的特性。特别是,我在现实世界中的代码中看到了这种模式,它导致了一个安全缺陷:
catch(FooException ex) { new BarException(ex); }
如果代码很复杂,那么发现这个缺陷可能会非常困难。
因此,编译器会检测由不在该列表中的表达式组成的所有语句。特别是,带括号的表达式被识别为带括号的表达。它们不在"允许作为语句表达式"的列表中,因此被禁止。
所有这些都是为C#语言的设计原则服务的如果您键入(x++);
,您可能做错了什么。这可能是M(x++);
的错别字,或者其他什么东西。请记住,C#编译器团队的态度不是"我们能想出一些方法来实现这一点吗?"C#编译器小组的态度是"如果看似合理的代码看起来像是一个可能的错误,让我们通知开发人员。C#开发人员喜欢这种态度。
尽管如此,实际上有一些奇怪的情况,C#规范确实暗示或明确声明不允许使用括号,但C#编译器无论如何都允许。在几乎所有这些情况下,指定行为和允许行为之间的微小差异是完全无害的,因此编译器编写人员从未修复过这些小错误。你可以在这里阅读:
return myVar和return(myVar)之间有区别吗?
在C#语言规范中
表达式语句用于计算表达式。可以用作语句的表达式包括方法调用、使用新运算符的对象分配、使用=和复合赋值运算符的赋值、使用++和--运算符的递增和递减操作以及等待表达式。
在语句周围加括号会创建一个新的所谓的带括号表达式。来自规范:
带括号的表达式由括号中的表达式组成。。。带括号的表达式是通过计算括号内的表达式来计算的。如果括号中的表达式表示命名空间或类型,则会发生编译时错误。否则,带括号的表达式的结果就是对包含的表达式求值的结果。
由于带括号的表达式未列为有效的表达式语句,因此根据规范,它不是有效的语句。为什么设计者选择这样做是任何人的猜测,但我敢打赌,因为如果整个语句都包含在括号中,括号就没有任何用处:stmt
和(stmt)
完全相同。
bea因为i++
周围的括号正在创建/定义一个表达式。。如错误消息所示。。一个简单的表达式不能用作语句。
为什么语言是这样设计的?为了防止错误,将误导性的表达式作为语句,不会产生任何副作用,比如使用代码
int j = 5;
j+1;
第二行没有效果(但你可能没有注意到)。但是,编译器并没有删除它(因为不需要代码)。它明确地要求你删除它(这样你就会知道错误),或者在你忘记键入内容的情况下修复它。
编辑:
使关于苦咸水的部分更加清晰。。c中的方括号(除了其他用途,如强制转换和函数调用)用于对表达式进行分组,并返回单个表达式(由子表达式组成)。
在该级别的代码中,只允许使用雄蕊。。所以
j++; is a valid statement because it produces side effects
但通过使用bracked,你将其转化为表达
myTempExpression = (j++)
和这个
myTempExpression;
无效,因为编译器无法将该表达式视为副作用。(并非没有陷入停顿的问题)。。