It's implied by other answers, and I endorse the suggestion from C++ to treat this as "a bad thing to do", but the "simple" fix is:
int x = 0;
x = Increment(ref x) + x;
Because C# ensures left to right evaluation of expressions*, this does what you expected.
*Quoting section "7.3 Operators" of the C# Spec:
Operands in an expression are evaluated from left to right. For example, in F(i) + G(i++) * H(i)
, method F
is called using the old value of i
, then method G
is called with the old value of i
, and, finally, method H
is called with the new value of i
. This is separate from and unrelated to operator precedence.
Note that last sentence means this:
int i=0, j=0;
Console.WriteLine(++j * (++j + ++j) != (++i + ++i) * ++i);
i = 0; j = 0;
Console.WriteLine($"{++j * (++j + ++j)} != {(++i + ++i) * ++i}");
i = 0; j = 0;
Console.WriteLine($"{++j} * ({++j} + {++j}) != ({++i} + {++i}) * {++i}");
outputs this:
True
5 != 9
1 * (2 + 3) != (1 + 2) * 3
and that last line can be "trusted" to be the same values as used in the previous two expressions. I.E. even though the addition is performed before the multiplication, because of the brackets, the operands have already been evaluated.
Note that "refactoring" this to:
i = 0; j = 0;
Console.WriteLine(++j * TwoIncSum(ref j) != TwoIncSum(ref i) * ++i);
i = 0; j = 0;
Console.WriteLine($"{++j * TwoIncSum(ref j)} != { TwoIncSum(ref i) * ++i}");
i = 0; j = 0;
Console.WriteLine($"{++j} * {TwoIncSum(ref j)} != {TwoIncSum(ref i)} * {++i}");
private int TwoIncSum(ref int parameter)
{
return ++parameter + ++parameter;
}
still works exactly the same:
True
5 != 9
1 * 5 != 3 * 3
But I still would prefer to not rely upon it :-)