Ok, this might be obvious for some of you but I am stumped with the behavior I'm getting from this rather simple code:
public static void Main(string[] args)
{
int? n = 1;
int i = 1;
n = ++n - --i;
Console.WriteLine("Without Nullable<int> n = {0}", n); //outputs n = 2
n = 1;
i = 1;
n = ++n - new Nullable<int>(--i);
Console.WriteLine("With Nullable<int> n = {0}", n); //outputs n = 3
Console.ReadKey();
}
I exepcted both outputs to be the same and equal to 2
but strangely enough they aren't. Can someone explain why?
EDIT: Although the code to generate this "weird" behavior is admittedly contrived, it does look like a bug in the C# compiler though seemingly unimportant and the reason seems to be the inlined new
as James pointed out initially. But the behavior is not limited to operations. Method calls behave exactly the same way, that is, they are called twice when they should only be called once.
Consider the following repro:
public static void Main()
{
int? n = 1;
int i = 1;
n = n - new Nullable<int>(sideEffect(ref i));
Console.WriteLine("With Nullable<int> n = {0}", n);
Console.ReadKey();
}
private static int sideEffect(ref int i)
{
Console.WriteLine("sideEffect({0}) called", i);
return --i;
}
Sure enough, output is 2
when it should be 1
and "sideEffect(i) called"
is printed out twice.
EDIT: This has been confirmed as a bug in the compiler by the team. It is fixed in Roslyn. As a workaround, use a cast (int?)(--i)
to stop the bug appearing, or don't explicitly cast it to a Nullable<int>
in the first place.
The first code block generates the following in reflector:
int? nullable3;
int? nullable = 1;
int num = 1;
int? nullable2 = nullable;
nullable2 = nullable = nullable2.HasValue
? new int?(nullable2.GetValueOrDefault() + 1)
: ((int?) (nullable3 = null));
int num2 = --num;
nullable = nullable2.HasValue
? new int?(nullable2.GetValueOrDefault() - num2)
: ((int?) (nullable3 = null));
Console.WriteLine("Without Nullable<int> n = {0}", nullable);
The second the following:
nullable = 1;
num = 1;
nullable2 = nullable;
nullable2 = nullable = nullable2.HasValue
? new int?(nullable2.GetValueOrDefault() + 1)
: ((int?) (nullable3 = null));
num2 = --num;
nullable = nullable2.HasValue
? new int?(nullable2.GetValueOrDefault() - --num)
: null;
Console.WriteLine("With Nullable<int> n = {0}", nullable);
They're more or less the same, up to the assignment to nullable
. It's running --num
twice, causing it to run 2 - -1
, resulting in 3.
It also does the same with expressions like i = ~i
, but not with method call expressions...
This is quite an interesting problem, from what I can see the compiler appears to evaluate the --
/++
statements more than once. For example, the following:
n = ++n - new Nullable<int>(i++)
results in n
becoming 0
(which you would expect) but i
is now 3
(which you would expect to be 2
). However, if I do
n = ++n - new Nullable<int>(i);
Then I get the expected result (n
= 1
and i
= 1
)
I can only assume this is somehow related to the new Nullable
call being in-line. I don't really see this as being much of an issue as this probably wouldn't be considered your everyday sort of code, however, in my opinion it does appear to be a bug with the compiler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With