以下代码是错误的(在ideone上看到它):
public class Test { public static void Main() { int j = 5; (j++); // if we remove the "(" and ")" then this compiles fine. } }
错误CS0201:只能将赋值,调用,递增,递减,等待和新对象表达式用作语句
为什么在删除括号时编译代码?
为什么不用括号编译?
为什么C#这样设计?
Eric Lippert.. 220
深刻的见解表示赞赏.
我会尽我所能.
正如其他答案所指出的,这里发生的是编译器检测到表达式被用作语句.在许多语言中--C,JavaScript和许多其他语言 - 将表达式用作语句是完全合法的. 2 + 2;
这些语言是合法的,即使这是一个没有效果的陈述.有些表达式只对它们的值有用,有些表达式只对它们的副作用有用(比如调用void返回方法),不幸的是,有些表达式对两者都很有用.(像增量一样.)
要点:只包含表达式的语句几乎肯定是错误的,除非这些表达式通常被认为对副作用比它们的值更有用.C#设计者希望通过允许通常被认为是副作用的表达来找到中间立场,同时禁止那些通常被认为对其价值有用的表达.他们在C#1.0中确定的表达式集是增量,减量,方法调用,赋值以及有点争议的构造函数调用.
ASIDE:人们通常认为物体结构用于产生它所产生的价值,而不是用于施工的副作用; 在我看来,允许new Foo();
有点不合时宜.特别是,我在实际代码中看到了这种模式导致了安全性缺陷:
catch(FooException ex) { new BarException(ex); }
如果代码复杂,可能会很难发现这个缺陷.
因此,编译器可以检测由不在该列表上的表达式组成的所有语句.特别是,带括号的表达式被标识为 - 带括号的表达式.它们不在"允许的语句表达式"列表中,因此不允许使用它们.
所有这些都是为了满足C#语言的设计原则.如果你打字,(x++);
你可能做错了什么.这可能是一个错字M(x++);
或一些正义的东西.请记住,C#编译器团队的态度是不是" 我们可以想出一些方法来使这项工作? " C#编译器团队的态度是" 如果可行的代码看起来像一个可能的错误,让我们通知开发商 ".C#开发人员喜欢这种态度.
现在,所有的说,其实有一些奇怪的情况下,C#的规格不暗示或直接说括号不允许的状态,但C#编译器允许他们反正.在几乎所有这些情况下,指定行为和允许行为之间的微小差异是完全无害的,因此编译器编写者从未修复过这些小错误.你可以在这里阅读:
返回myVar与return(myVar)之间有区别吗?
深刻的见解表示赞赏.
我会尽我所能.
正如其他答案所指出的,这里发生的是编译器检测到表达式被用作语句.在许多语言中--C,JavaScript和许多其他语言 - 将表达式用作语句是完全合法的. 2 + 2;
这些语言是合法的,即使这是一个没有效果的陈述.有些表达式只对它们的值有用,有些表达式只对它们的副作用有用(比如调用void返回方法),不幸的是,有些表达式对两者都很有用.(像增量一样.)
要点:只包含表达式的语句几乎肯定是错误的,除非这些表达式通常被认为对副作用比它们的值更有用.C#设计者希望通过允许通常被认为是副作用的表达来找到中间立场,同时禁止那些通常被认为对其价值有用的表达.他们在C#1.0中确定的表达式集是增量,减量,方法调用,赋值以及有点争议的构造函数调用.
ASIDE:人们通常认为物体结构用于产生它所产生的价值,而不是用于施工的副作用; 在我看来,允许new Foo();
有点不合时宜.特别是,我在实际代码中看到了这种模式导致了安全性缺陷:
catch(FooException ex) { new BarException(ex); }
如果代码复杂,可能会很难发现这个缺陷.
因此,编译器可以检测由不在该列表上的表达式组成的所有语句.特别是,带括号的表达式被标识为 - 带括号的表达式.它们不在"允许的语句表达式"列表中,因此不允许使用它们.
所有这些都是为了满足C#语言的设计原则.如果你打字,(x++);
你可能做错了什么.这可能是一个错字M(x++);
或一些正义的东西.请记住,C#编译器团队的态度是不是" 我们可以想出一些方法来使这项工作? " C#编译器团队的态度是" 如果可行的代码看起来像一个可能的错误,让我们通知开发商 ".C#开发人员喜欢这种态度.
现在,所有的说,其实有一些奇怪的情况下,C#的规格不暗示或直接说括号不允许的状态,但C#编译器允许他们反正.在几乎所有这些情况下,指定行为和允许行为之间的微小差异是完全无害的,因此编译器编写者从未修复过这些小错误.你可以在这里阅读:
返回myVar与return(myVar)之间有区别吗?
在C#语言规范中
表达式语句用于计算表达式.可用作语句的表达式包括方法调用,使用new运算符的对象分配,使用=的赋值和复合赋值运算符,使用++和 - 运算符的增量和减量运算以及await表达式.
将括号括在语句周围会创建一个新的所谓括号表达式.从规格:
括号表达式由括在括号中的表达式组成....通过计算括号内的表达式来计算括号表达式.如果括号内的表达式表示名称空间或类型,则会发生编译时错误.否则,parenthesized-expression的结果是包含表达式的计算结果.
由于带括号的表达式未列为有效的表达式语句,因此根据规范,它不是有效的语句.为什么设计师选择这样做是任何人的猜测,但我的赌注是因为如果整个陈述包含在括号中,括号不起作用:stmt
并且(stmt)
完全相同.
因为周围的括号i++
正在创建/定义表达式..因为错误消息说...一个简单的表达式不能用作语句.
为什么语言设计成这种方式?防止错误,将错误的表达式作为语句,不产生像代码一样的副作用
int j = 5; j+1;
第二行没有效果(但你可能没有注意到).但不是编译器删除它(因为代码不需要).明确要求你删除它(所以你会意识到或错误)或修复它,以防你忘记输入内容.
编辑:
使关于bracked的部分更清晰.. c#中的括号(除了其他用途,如强制转换和函数调用),用于对表达式进行分组,并返回单个表达式(子表达式的make).
在那个级别的代码中只允许staments ..所以
j++; is a valid statement because it produces side effects
但是通过使用bracked你将它变成表达式
myTempExpression = (j++)
还有这个
myTempExpression;
是无效的,因为编译器不能确保表达式作为副作用.(不是没有引起停止问题)..