To start with something simple, we can all agree on the fact that the following code snippet
int a = 10; int b = a++;
stores 10 in a variable a, then copies the value to a variable b and increases value stored in the variable a to 11. But what the following code does?
int a = 10; a = a++;
In order to be sure, let’s peek at generated IL code (you can try it yourself using LINQPad, for instance).
IL_0001: ldc.i4.s 0A // stack: 10 IL_0003: stloc.0 // a = 10, stack: empty IL_0004: ldloc.0 // stack: 10 IL_0005: dup // stack: 10, 10 IL_0006: ldc.i4.1 // stack: 10, 10, 1 IL_0007: add // stack: 10, 11 IL_0008: stloc.0 // a = 11, stack: 10 IL_0009: stloc.0 // a = 10, stack: empty
I supplemented the output by comments to see what’s happening on the evaluation stack. As you can see, in order to be able to return the previous value, it’s preserved by duplicating it first, then increment takes place followed by an assigment of the new value to the variable and finally the old value returned (as post-increment promises) and assigned to the variable.
I consider the previous nearly self-explanatory and I could leave it as it is now, but admittedly, it’s not always enough to look at the corresponding IL to understand or even start with it for that matter. Therefore, remember that the right side expression of an assignment statement is always evaluated first in .NET. It’s a well defined behaviour of operator precedence and associativity.
To use it in our situation - a++ expression is completely evaluated before a value it returns is assigned to a variable on the left side, which means, that a is really 11 for a moment before it’s overwritten by the previous value.