Nullable types and the ternary operator: why is `? 10 : null` forbidden?
C#.NetNullableConditional OperatorC# Problem Overview
I just came across a weird error:
private bool GetBoolValue()
{
//Do some logic and return true or false
}
Then, in another method, something like this:
int? x = GetBoolValue() ? 10 : null;
Simple, if the method returns true, assign 10 to the Nullableint
x. Otherwise, assign null to the nullable int. However, the compiler complains:
> Error 1 Type of conditional expression cannot be determined because there is no implicit conversion between int
and <null>
.
Am I going nuts?
C# Solutions
Solution 1 - C#
The compiler first tries to evaluate the right-hand expression:
GetBoolValue() ? 10 : null
The 10
is an int
literal (not int?
) and null
is, well, null
. There's no implicit conversion between those two hence the error message.
If you change the right-hand expression to one of the following then it compiles because there is an implicit conversion between int?
and null
(#1) and between int
and int?
(#2, #3).
GetBoolValue() ? (int?)10 : null // #1
GetBoolValue() ? 10 : (int?)null // #2
GetBoolValue() ? 10 : default(int?) // #3
Solution 2 - C#
Try this:
int? x = GetBoolValue() ? 10 : (int?)null;
Basically what is happening is that conditional operator is unable to determine the "return type" of the expression. Since the compiler implictitly decides that 10
is an int
it then decides that the return type of this expression shall be an int
as well. Since an int
cannot be null
(the third operand of the conditional operator) it complains.
By casting the null
to a Nullable<int>
we are telling the compiler explicitly that the return type of this expression shall be a Nullable<int>
. You could have just as easily casted the 10
to int?
as well and had the same effect.
Solution 3 - C#
Incidentally, the Microsoft implementation of the C# compiler actually gets the type analysis of the conditional operator wrong in a very subtle and interesting (to me) way. My article on it is Type inference woes, part one (2006-05-24).
Solution 4 - C#
Try this:
int? result = condition ? 10 : default(int?);
Solution 5 - C#
Try one of these:
int? x = GetBoolValue() ? (int?)10 : null;
int? x = GetBoolValue() ? 10 : (int?)null;
Solution 6 - C#
The problem is that the ternary operator is inferring type based on your first parameter assignment...10 in this case, which is an int, not a nullable int.
You might have better luck with:
int? x = GetBoolValue() (int?)10 : null;
Solution 7 - C#
int? x = GetBoolValue() ? 10 : (int?)null;
The reason you see this is because behind the scenes you're using Nullable
Solution 8 - C#
Just add an explict cast.
int? x = GetBoolValue() ? 10 : (int?)null;
It is the ternary operator that gets confused - the second argument is an integer and so is the third argument exspected to be an integer, too, and null does not fit.
Solution 9 - C#
It's because the compiler determines the type of the conditional operator by its second and third operand, not by what you assign the result to. There is no direct cast between an integer and an null reference that the compiler can use to determine the type.