C#编译器行为问题?

C# Compiler Behavior Question?

大家好,在下面的代码中,第二个表达式后面的d结果应该是什么?

1
2
        int d = 1;
        d += d++;

之后我们假设d为3,但一元增量d++似乎没有生效,d保留2的值。

这个bug有名字吗?它是否存在于其他支持一元增量(如c_)的编译器中?


这不是一个bug,它的行为和预期的完全一样。

+=运算符展开为:

1
d = d + d++;

这意味着当结果被分配回变量时,++运算符导致的更改将被覆盖。


如果您查看生成的IL,您将看到为什么结果是2而不是3。

1
2
3
4
5
6
7
8
9
10
11
12
13
IL_0000:  ldc.i4.1  // load constant 1 on evaluation stack
IL_0001:  stloc.0   // pop and store value in local 0
IL_0002:  ldloc.0   // load value of local 0 on evaluation stack
IL_0003:  ldloc.0   // repeat, stack is now 1, 1
IL_0004:  dup       // duplicate topmost value on evaluation stack,
                    // i.e. stack is now 1, 1, 1
IL_0005:  ldc.i4.1  // load constant 1 on evaluation stack
IL_0006:  add       // add two topmost values on stack,
                    // i.e. 1 and 1 and push result on stack
IL_0007:  stloc.0   // pop and store this value in local 0
IL_0008:  add       // add the two remaining values on the stack
                    // which again happens to be 1 and 1 and push result to stack
IL_0009:  stloc.0   // pop and store this value in local 0

换句话说:存储的最终值是1和1的总和。

(以上代码来自发布模式构建)


如果您以这种方式重写代码,它将设置为d的值为3:

1
2
int d = 1;
d += ++d;

请查看++操作员文档,以获取有关示例行为方式的解释。
Excerpt:

The second form is a postfix increment
operation. The result of the operation
is the value of the operand before it
has been incremented.

正如@guffa指出的,这不是一个bug,只是您在d中的后缀增量操作的结果被+=操作覆盖了。


我经常遇到关于++操作符"被破解"的问题,几乎总是这样,因为提问的人习惯于在某些语言中工作的方式,其中行为+ +没有明确定义,比如C++。我最近写了一篇关于这种情况的文章:

http://blogs.msdn.com/ericlippet/archive/2009/08/10/precedence-vs-order-redux.aspx


我认为d++的行为不同于++d的行为,尽管存储在d中的最终结果是相同的。


你试过+d吗?D++不是在之后计算的吗?


…这就是我发现后/前递增/递减运算符在表达式中与其他运算符一起使用时高度不可读的原因的一个例子。你描述的行为是正确的,但很难解释,导致误解和错误。

尽管更为冗长,我还是将其改写为:

1
2
3
int d = 1;
d += d;
++d;

注意使用预增量运算符而不是后增量,这样编译器就不需要保留旧值的副本。


D++和+D是不同的。也称为"选择未中断"。


愚蠢的代码是不可预测的。我能推荐一下吗

1
d += 2;