Note: this appears to have been fixed in Roslyn
This question arose when writing my answer to this one, which talks about the associativity of the n
If you take a look at the generated code for the Left-grouped case it actually does something like this (csc /optimize-
):
C? first;
A? atemp = a;
B? btemp = (atemp.HasValue ? new B?(a.Value) : b);
if (btemp.HasValue)
{
first = new C?((atemp.HasValue ? new B?(a.Value) : b).Value);
}
Another find, if you use first
it will generate a shortcut if both a
and b
are null and return c
. Yet if a
or b
is non-null it re-evaluates a
as part of the implicit conversion to B
before returning which of a
or b
is non-null.
From the C# 4.0 Specification, §6.1.4:
- If the nullable conversion is from
S?
toT?
:
- If the source value is
null
(HasValue
property isfalse
), the result is thenull
value of typeT?
.- Otherwise, the conversion is evaluated as an unwrapping from
S?
toS
, followed by the underlying conversion fromS
toT
, followed by a wrapping (§4.1.10) fromT
toT?
.
This appears to explain the second unwrapping-wrapping combination.
The C# 2008 and 2010 compiler produce very similar code, however this looks like a regression from the C# 2005 compiler (8.00.50727.4927) which generates the following code for the above:
A? a = x;
B? b = a.HasValue ? new B?(a.GetValueOrDefault()) : y;
C? first = b.HasValue ? new C?(b.GetValueOrDefault()) : z;
I wonder if this is not due to the additional magic given to the type inference system?