Pre- & Post Increment in C#
x--
will be 4, but will be 3 at the moment of --x
, so it will end being 2, then you'll have
x = 4 - 2
btw, your first case will be x = 4 + 6
Here is a small example that will print out the values for each part, maybe this way you'll understand it better:
static void Main(string[] args)
{
int x = 4;
Console.WriteLine("x++: {0}", x++); //after this statement x = 5
Console.WriteLine("++x: {0}", ++x);
int y = 4;
Console.WriteLine("y--: {0}", y--); //after this statement y = 3
Console.WriteLine("--y: {0}", --y);
Console.ReadKey();
}
this prints out
x++: 4
++x: 6
y--: 4
--y: 2
C# post increment and pre increment
Difference is, what the operator returns:
The post-increment operator "a plus plus" adds one, and returns the old value:
int a = 1;
int b = a++;
// now a is 2, b is 1
The pre-increment operator "plus plus a" adds one, and returns the new value:
a = 1;
b = ++a;
// now a is 2 and b is 2
Pre and post increment/decrement operators in C#
you are running one of the operands on the result of the other, the result of a increment/decrement is a value - and you can not use increment/decrement on a value it has to be a variable that can be set.
Simultaneous pre-increment and post-increment or mixing pre-post increments
The result of (x++) or (++x) is not actually a variable. It's a value, so:
int y = (++x) + 1;
// evaluates to
int y = (1) + 1;
but
int y = ++x++;
// is equivalent to
int y = ++(x++);
// evaluates to
int y = ++(0);
Difference between pre-increment and post-increment in a loop?
a++ is known as postfix.
add 1 to a, returns the old value.
++a is known as prefix.
add 1 to a, returns the new value.
C#:
string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
Console.WriteLine(++i);
}
Console.WriteLine("");
i = 0;
foreach (string item in items)
{
Console.WriteLine(i++);
}
Output:
1
2
3
4
0
1
2
3
foreach
and while
loops depend on which increment type you use. With for loops like below it makes no difference as you're not using the return value of i:
for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }
0 1 2 3 4
0 1 2 3 4
If the value as evaluated is used then the type of increment becomes significant:
int n = 0;
for (int i = 0; n < 5; n = i++) { }
Pre & post increment operator behavior in C, C++, Java, & C#
Java and C# evaluate expressions from left to right, and the side-effects are visible immediately.
In C++, the order of evaluation of subexpressions is unspecified, and modifying the same object twice without an intervening sequence point is undefined behavior.
Unexpected post-increment behavior in assignment
For me the best way to understand some behaviour is to check IL generated. In your first case it's
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
IL_000A: ldloc.0 // stack: 10
IL_000B: call System.Console.WriteLine
You can see that there's still that original value hanging on the stack and so the created 11 gets overwritten in the end.
Let me try to explain it in plain words.
When you are assigning a value to a variable (a = a++
) the whole right side of the assignment gets evaluated first in order to guarantee the correct value, that's how it is. So nothing like you get 10, application goes on and increments value when you execute the next line.
Now, imagine post-increment as someone, who first increments a value, but gave you his world that you will get back the original value from the expression. And now you should see why the 11 is overwritten. Increment goes first and in the end, you get the promise original value (as IL proves).
Post-increment within a self-assignment
Let’s take a look at the intermediary language code for that:
IL_0000: nop
IL_0001: ldc.i4.s 2A
IL_0003: stloc.0 // c
IL_0004: ldloc.0 // c
This loads the constant integer 42
onto the stack, then stores it into the variable c
, and loads it immediately again onto the stack.
IL_0005: stloc.1
IL_0006: ldloc.1
This copies the value into another register, and also loads it again.
IL_0007: ldc.i4.1
IL_0008: add
This adds the constant 1 to the loaded value
IL_0009: stloc.0 // c
… and stores the result (43) into the variable c
.
IL_000A: ldloc.1
IL_000B: stloc.0 // c
Then the value from the other register is loaded (that’s still 42!) and stored into the variable c
.
IL_000C: ldloc.0 // c
IL_000D: call System.Console.WriteLine
IL_0012: nop
IL_0013: ret
Then the value (42) is loaded from the variable, and printed.
So what you can see from this is that while c++
increments the variable by one after the result was returned, that incrementing happens still before assinging the value to the variable. So the sequence is more like this:
- Get value from
c
- Post-increment
c
- Assign previously read value to
c
And that should explain why you get that result :)
To add one more example, since this was mentioned in a comment that was since deleted:
c = c++ + c;
This works very similarly: Assuming an initial value of 2 again, the left side of the addition is evaluated first. So the value is read from the variable (2), then c
is incremented (c
becomes 3). Then the right side of the addition is evaluated. The value of c
is read (now 3). Then the addition takes place (2 + 3) and the result (5) is assigned to the variable.
The takeaway from this is that you should avoid mixing increment and decrement operations in normal expressions. While the behavior is very well defined and makes absolute sense (as shown above), it is still sometimes difficult to wrap your head around it. Especially when you assign something to the same variable that you increment in the expression, this becomes confusing quickly. So do yourself and others a favor and avoid increment/decrement operations when they are not completely on their own :)
Related Topics
How to Return a File Using Web API
Non-Static Method Requires a Target
Copy Rows from One Datatable to Another Datatable
Creating a Very Simple Linked List
What's Better: Dataset or Datareader
Access to Foreach Variable in Closure Warning
Send Smtp Email Using System.Net.Mail via Exchange Online (Office 365)
Converting from Ienumerable to List
Programmatically Get the Version Number of a Dll
Does Using Tasks (Tpl) Library Make an Application Multithreaded
Convert String to Hex-String in C#
Mvvm Light 5.0: How to Use the Navigation Service
Algorithm to Find Which Numbers from a List of Size N Sum to Another Number