I add an unexpected behaviour from C#/WPF
private void ButtonUp_Click(object sender, RoutedEventArgs e)
{
int quant;
if( int.TryParse(Qnt.Text, out quant))
{
string s = ((quant++).ToString());
Qnt.Text = s;
}
}
So, if I get quant as 1, quant will be incremented to 2. But the s string will be 1. Is this a question of precedence?
EDIT:
I re-wrote this as:
quant++;
Qnt.Text = quant.ToString();
and now this works as I expected.
You are using the post-increment operator. This evalutates to the original value, and then increments. To do what you want in a one-liner you can use the pre-increment operator instead.
(++quant).ToString();
But even better would be to avoid all such pitfalls and do it like this:
quant++;
string s = quant.ToString();
With the first version you have to think about the order in which things happen. In the second version no thought is required. Always value code clarity more highly than conciseness.
It's easy to believe that the one-line version is somehow faster, but that's not true. It might have been true back in the day in 1970s C systems, but even then that I doubt.
The problem is that you're using a post-increment instead of a pre-increment... but why would you want to write this convoluted code? Just separate out the side-effect (incrementing) and the ToString call:
if (int.TryParse(Qnt.Text, out quant))
{
quant++;
Qnt.Text = quant.ToString();
}
Or even forego the actual increment given that you're not going to read the value again:
if (int.TryParse(Qnt.Text, out quant))
{
Qnt.Text = (quant + 1).ToString();
}
Where possible, avoid using compound assignment in the middle of other expressions. It generally leads to pain.
Additionally, it feels like all this parsing and formatting is hiding the real model, which is that there should be an int
property somewhere, which might be reflected in the UI. For example:
private void ButtonUp_Click(object sender, RoutedEventArgs e)
{
// This is an int property
Quantity++;
// Now reflect the change in the UI. Ideally, do this through binding
// instead.
Qnt.Text = Quantity.ToString();
}
Now I'll do something that shouldn't be done... I'll try to simplify what Eric Lippert wrote here What is the difference between i++ and ++i? I hope I'm not writing anything too much wrong :-)
Now... What does the pre-increment and post-increment operators do? Simplifying and ignoring all the copy that are done in-between (and remembering that they aren't atomic operators in multi-threaded environments):
both of them are expressions (like i + 1
) that return a result (like i + 1
) but that have a side-effect (unlike i + 1
). The side-effect is that they increment the variable i
. The big question is "in which order everything happens?" The answer is quite simple:
- pre increment
++i
: incrementsi
and returns the new value ofi
- post increment
i++
: incrementsi
and returns the old value ofi
Now... The important part is that the increments i
always happens first. Then a value (the old or the new) is returned.
Let's make an example (the example of Lippert is quite complex. I'll make a different, more simple example, that isn't as much complete but that is enough to check if the order I said before is right or not) (technically I'll make two examples)
Example 1:
unchecked
{
int i = Int32.MaxValue;
Console.WriteLine("Hello! I'm trying to do my work here {0}", i++);
Console.WriteLine("Work done {1}", i);
}
Example 2:
checked
{
int i = Int32.MaxValue;
Console.WriteLine("Hello! I'm trying to do my work here {0}", i++);
Console.WriteLine("Work done {1}", i);
}
checked
means that if there is an overflow an exception (OverflowException
) will be thrown. unchecked
means that the same operation won't throw an exception. Int32.MaxValue + 1
surely will overflow. With checked
there will be an exception, with unchecked
i
will become -1.
Let's try running the first code piece. Result:
Hello! I'm trying to do my work here 2147483647
Work done -1
Ok... The i
was incremented but the Console.WriteLine
received the old value (Int32.MaxValue == 2147483647
). From this example we can't determine the order of the post-increment and of the calling of Console.WriteLine
.
Let's try running the second code piece. Result:
System.OverflowException: Arithmetic operation resulted in an overflow.
Ok... It's quite clear that first the post-increment was executed, caused an exception, and then clearly the Console.WriteLine
wasn't executed (because the program ended).
So we know that the order I said is the right one.
Now. What should you learn from this example? The same thing I learned many years ago. Pre and post increments in C and C# are good for obfuscated code contests. They aren't good for many other things (but note that C++ is different!). From that lesson I learned that there are exactly two places where you can use post-increment freely, and there are exactly zero places where you can use pre-increment freely.
"Safe" post-increment
for (int i = 0; i < x; i++)
and
i++; // Written alone. Nothing else on the same line but a comment if necessary.
"Safe" pre-increment
(nothing)
In this case, first quant.ToString()
will be called and then quant will be incremented.
If you write ((++quant).ToString())
the first step will be incrementing quant and then quant.ToString()
will be called.
string s = ((quant++).ToString());
can be distributed as
use quant
for toString() method call before incrementing, and then
execute assignment operator, and then
increment `quant'
try with ++quant.
来源:https://stackoverflow.com/questions/7848104/c-sharp-increment-tostring