In C# why can't a conditional operator implicitly cast to a nullable type
I am curious as to why an implicit cast fails in...
int? someValue = SomeCondition ? ResultOfSomeCalc() : null;
and why I have to perform an explicit cast instead
int? someValue = SomeCondition ? ResultofSomeCalc() : (int?)null;
It seems to me that the compiler has all the information it need to make an implicit casting decision, no?
The relevant section of the C# 3.0 spec is 7.13, the conditional operator:
The second and third operands of the ?: operator control the type of the conditional expression. Let X and Y be the types of the second and third operands. Then,
If X and Y are the same type, then this is the type of the conditional Otherwise, if an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression. Otherwise, if an implicit conversion (§6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression. Otherwise, no expression type can be determined, and a compile-time error occurs.
I also am annoyed that it can't infer the type based on the assignment, especially when it's a value type. There are reasons though when you get into object heirarchies.
If "ResultOfSomeCalc()" returned a "int?", then this would work. C# needs to figure out the type regardless of what is to the left of the assignment. So you are telling it that you'll return a null or an int - and the logic in the compiler doesn't exist to have it substitute a Nullable as a common denominator.
Notice that these variants DO work, and it may help you understand:
object someValue = true ? new Nullable<int>(ResultOfSomeCalc()) : null;
object someValue = true ? (int?)ResultOfSomeCalc() : null;
Hope this helps.
It sure seems like this is something the compiler should be able to figure out for itself, but there is one other way to do this, using the default keyword. It might be the tiniest bit less ugly than the cast:
int? someValue = SomeCondition ? ResultofSomeCalc() : default(int?);
This use of default doesn't seem to be well documented, but is does work. At least it keeps you from having to litter your code with magic values (I contend that null/zero/false/etc. are indeed magic values).
See also Why is this code invalid in C#?