为什么Postfix ++ / – 在C#中被归类为主要操作符?

目前我正在教授一类C ++程序员C#语言的基础知识。 当我们讨论主题运算符时,我使用C#标准类别的主要,一元等操作符。

其中一位与会者感到困惑,因为在C#标准中,“postfix ++ / – ”已经被置于主要运营商的类别而不是“前缀++ / – ”。 她混淆的理由是,她宁愿用运算符“prefix ++ / – ”来实现C ++运算符“postfix ++ / – ”。 换句话说,她宁愿将运算符“prefix ++ / – ”视为主要运算符。 – 我理解她的观点,但我不能给她一个理由。 好吧,运营商“postfix ++ / – ”的优先级高于“前缀++ / – ”,但这背后的唯一理由是什么?

规范在“14.2.1运算符优先级和关联性”一节中提到了它。

所以我非常中立的问题:为什么Postfix ++ / – 在C#中被归类为主要操作符? 它有更深层次的真相吗?

由于ECMA标准本身没有定义“主要”运算符是什么,除了优先顺序(即在“一元”之前出现)之外,没有其他意义。 单词的选择可能很糟糕。

考虑到在许多C-link语言中,后缀运算符倾向于创建一个临时变量,其中存储表达式的中间结果(请参阅: “在Semicolon上优先使用前缀运算符over postfix” )。 因此,它们与前缀版本根本不同。

尽管如此,我快速检查Mono和Visual Studio如何使用后缀和前缀forms编译for循环,我看到生成的IL代码是相同的。 只有当你使用postfix / prefix表达式的值时,它才会转换为不同的IL(仅影响放置’dup’指令的位置),至少对于那些提到的实现。

编辑:好的,现在我回到家了,我已经删除了大部分令人困惑的部分……

我不知道为什么x++被归类为主要表达式,但++x不是; 虽然我怀疑它会对您编写的代码产生很大影响。 同上优先。 我想知道后缀是否被认为是主要的,因为它更常用? 顺便说一句,在ECMA版本或Microsoft C#4版本中,带注释的C#规范没有任何注释。 (我无法立即找到我的C#3版本进行检查。)

但是,就实现而言,我认为++是一种伪运算符,由前缀和后缀表达式使用。 特别是,当您重载++运算符时,该重载用于后缀和前缀增量。 这与C ++不同,正如stakx在评论中指出的那样。

需要注意的一点是,虽然后递增/后递减表达式必须具有主表达式作为操作数,但是预递增/预递减表达式只需要将一元表达式作为操作数。 在这两种情况下,操作数必须被分类为变量,属性访问或索引器访问,所以我不确定实际的差异,如果有的话。

编辑:只是给另一点评论,即使它似乎是任意的,我同意它看起来似乎奇怪的规范:

主要表达式包括最简单的表达forms

但是,预增量的步骤列表比后增量的步骤列表更短/更简单(因为它不包括“保存值”步骤)。

区别在于[i ++]将访问索引为i的元素。

a [++ i]将访问索引为i + 1的元素。

在执行[++ i / i ++]后的两种情况下

我将是i + 1。

这可能会造成麻烦,因为您无法对参数顺序进行假设

function(I + +,我+ +,我++)

将增加我3次,但你不知道按顺序。 如果最初我是4你也可以有function(4,5,6)

还有function(6,5,4)或function(6,4,5)。

并且这仍然没有,因为我用作示例本机类型(例如“int”),当你有类时情况变得更糟。

当重载操作符结果没有改变时,改变的是它的优先级。 这也会引起麻烦。

因此,在一种情况下,在返回引用之前应用“++”,而在另一种情况下,在“返回”引用之后应用“++”。 当你重载它时,最好在返回引用之前应用它(所以++至少从重载的角度来看,比某些东西要好得多。)

采用带有重载++的generics类(我们有2个项目,foo和bar)

  foo = bar ++; //is like writing (foo=bar).operator++(); foo = ++bar; // is like writing foo= (bar.operator++()); 

而且有很大的不同。 特别是当你没有分配你的引用但是做一些更复杂的引用时,或者在内部你的对象有与浅拷贝VS深拷贝有关的东西。