Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit casting of Null-Coalescing operator result

With the following understanding about null coalescing operator (??) in C#.

int? input = -10;
int result = input ?? 10;//Case - I
//is same as:
int result = input == null? input : 10; // Case - II

While, by definition and usage, Case I and Case II are same.

It is surprising to see that in Case-I compiler is able to implicitly cast int? to int while in Case-II it shows error: 'Error 1 Cannot implicitly convert type 'int?' to 'int'"

What is it that I am missing about null-coalescing operator?

Thanks for your interest.

like image 930
Manish Basantani Avatar asked Jan 17 '12 16:01

Manish Basantani


2 Answers

To make the second case work with the ternary operator, you could use the following:

int result = input != null ? input.Value : 10;

The Value property of the Nullable<T> type returns the T value (in this case, the int).

Another option is to use Nullable<T>.HasValue:

int result = input.HasValue ? input.Value : 10;

The myNullableInt != null construct is only syntactic sugar for the above HasValue call.

like image 163
Platinum Azure Avatar answered Nov 19 '22 16:11

Platinum Azure


This behavior you have observed for the null-coalescing operator ?? is a documented language feature, see section 7.13 of the C# 4.0 Language Specification for more details.

The type of the expression a ?? b depends on which implicit conversions are available on the operands. In order of preference, the type of a ?? b is A0, A, or B, where A is the type of a (provided that a has a type), B is the type of b (provided that b has a type), and A0 is the underlying type of A if A is a nullable type, or A otherwise. Specifically, a ?? b is processed as follows:

  • If A exists and is not a nullable type or a reference type, a compile-time error occurs.

  • If b is a dynamic expression, the result type is dynamic. At run-time, a is first evaluated. If a is not null, a is converted to dynamic, and this becomes the result. Otherwise, b is evaluated, and this becomes the result.

  • Otherwise, if A exists and is a nullable type and an implicit conversion exists from b to A0, the result type is A0. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0, and this becomes the result. Otherwise, b is evaluated and converted to type A0, and this becomes the result.

  • Otherwise, if A exists and an implicit conversion exists from b to A, the result type is A. At run-time, a is first evaluated. If a is not null, a becomes the result. Otherwise, b is evaluated and converted to type A, and this becomes the result.

  • Otherwise, if b has a type B and an implicit conversion exists from a to B, the result type is B. At run-time, a is first evaluated. If a is not null, a is unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. Otherwise, b is evaluated and becomes the result.

  • Otherwise, a and b are incompatible, and a compile-time error occurs.

See section 7.14 for why the conditional operator a ? b : c works differently.

Download the specification to read both in completeness at your leisure.

like image 44
Anthony Pegram Avatar answered Nov 19 '22 14:11

Anthony Pegram