Why does null need an explicit type cast here? [duplicate]
The following code does not compile:
//int a = ...
int? b = (int?) (a != 0 ? a : null);
In order to compile, it needs to be changed to
int? b = (a != 0 ? a : (int?) null);
Since both b = null
and b = a
are legal, this doesn't make sense to me.
Why do we have to cast the null
into an int?
and why can't we simply provide an explicit type cast for the whole expression (which I know is possible in other cases)?
From chapter 7.13 of the C# Language Specification:
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 expression.
- 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.
In your case, there is no implicit conversion from int to null nor the other way around. Your cast solves the problem, int is convertible to int?
The both alternatives of ?:
operator must be of the same type.
Otherwise, the compiler cannot deduce the type of the whole conditional expression.
null
is not an int
, so you need to give a hint to the compiler that the resulting type is int?
.
Edit: as the others pointed out, the two types don't need to be the same, but one of them should be castable to another (that another one will be the result type). See specs for more details.
You can save yourself from casting if you use default(int?)
instead of null
.
int a = 42;
int? b = (a != 0 ? a : default(int?));
it's because when you use that kind of notation, both member must be of the same type, so you have to explicitly say "this member is a int?".
is it clear ?
When you use the conditional operator with operands of different types, the compiler will check whether one of the types can be implicitly converted to the other type.
If neither type can be implicitly converted to the other one, it will give an error, even if there is a third type that they can both implicitly convert to. The compiler will not insert an implicit conversion on both sides at once.
In your case, both int
and null
requires implicit conversions to become int?
, so it doesn't work.
You need to change your code so that one side is an int?
and the other side can be implicitly converted to int?
. The simplested way to do this is to replace null
with new int?()
, like this:
int? b = (a != 0 ? a : new int?());
This only requires one implicit conversion (int
to int?
).
This is pretty much a duplicate of one of my questions, regarding the conditional operator. It's not the null, it really is the :
.
The answer accepted there is pretty good, from none other than Eric Lippert, who is on the C# compiler team.
精彩评论