Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why assigning null in ternary operator fails: no implicit conversion between null and int?

This fails with a There is no implicit conversion between 'null' and 'int'

long? myVar = Int64.Parse( myOtherVar) == 0 ? null : Int64.Parse( myOtherVar);

However, this succeeds:

if( Int64.Parse( myOtherVar) == 0)
    myVar = null;
else
    myVar = Int64.Parse( myOtherVar);

Is there a way to make the ternary operator succeed?

like image 440
Zachary Scott Avatar asked Nov 27 '10 05:11

Zachary Scott


3 Answers

The compiler ignores the left-hand side when figuring out the type of the right-hand side. So when it tries to deduce the type of

Int64.Parse(myOtherVar) == 0 ? null : Int64.Parse(myOtherVar)

it does so without paying any attention to the fact the left-hand side is a long?. To determine the type of the right-hand side it notes that

Int64.Parse(myOtherVar)

is a long and now tries to see if null is or can be implicitly converted to a long. Since it can not, you get the error message that you see.

From §7.14 of the C# specification:

A conditional expression of the form b ? x : y....

The second and third operands, x and y, of the ?: operator control the type of the conditional expression.

(1) If x has type X and y has type Y then

a. 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.

b. 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.

c. Otherwise, no expression type can be determined, and a compile-time error occurs.

(2) If only one of x and y has a type, and both x and y, of areimplicitly convertible to that type, then that is the type of the conditional expression.

(3) Otherwise, no expression type can be determined, and a compile-time error occurs.

Note that we are in situation (2) where x is null and does not have a type and y is Int64.Parse(myOtherVar) and has type long. Note that x is not implicitly convertible to the type of y. Therefore both (1) and (2) fail above and we result in (3) which results in the compile-time error that inspired your question. Note the implicit conclusion from the above that the left-hand side does not play a role in determining the type of right-hand side.

To rectify this replace

Int64.Parse(myOtherVar)

with

(long?)Int64.Parse(myOtherVar)

Now, the reason why

myVar = null;

is okay where myVar is declared as long? is because the compiler knows there is an implicit conversion from null to long?.

Lastly, Int64.Parse will throw if myOtherVar can't be parsed to a long. Note that you are also performing the parse twice, which is unnecessary. A better pattern is

long value;
if(Int64.TryParse(myOtherVar, out value)) {
    myVar = value == 0 ? null : (long?)value;
}
else {
    // handle case where myOtherVar couldn't be parsed
}
like image 103
jason Avatar answered Oct 19 '22 06:10

jason


Your operator usage is returning an Int64, not a nullable one, because of the last part of the ternary operator. It may work if you do instead:

long? myVar = Int64.Parse( myOtherVar) == 0 ? null :
   (long?)Int64.Parse( myOtherVar);

So that you are returning a long? instead, so the null doesn't need to be converted to Int64

Also, you are converting the value twice in your code, unnecessarily (once to test, and once to get the value). Your code might be better thus:

long? tempVar = Int64.Parse(myOtherVar);
long? myVar = tempVar==0? null : tempVar;
like image 29
Andrew Barber Avatar answered Oct 19 '22 05:10

Andrew Barber


I am sure you meant to say:

  myVar = value == 0 ? null : (long?)value;

instead of

  myVar = value == 0 ? null : value;

I liked the usage of the 'out' variable. Thanks.

like image 21
Prasanna K Rao Avatar answered Oct 19 '22 04:10

Prasanna K Rao