I would expect the next three lines of code to be the same:
public static void TestVarCoalescing(DateTime? nullableDateTime)
{
var dateTimeNullable1 = nullableDateTime.HasValue ? nullableDateTime : DateTime.Now;
var dateTimeNullable2 = nullableDateTime != null ? nullableDateTime : DateTime.Now;
var dateTimeWhatType = nullableDateTime ?? DateTime.Now;
}
In all cases, I assign nullableDateTime
to the new variable. I would expect the type of all variables to become DateTime?
since that is the type of nullableDateTime
. But to my surprise, the type of dateTimeWhatType
just becomes DateTime
, so not nullable.
To make things worse, ReSharper suggests to replace the second statement with a null coalescing expression, turning it into expression 3. So if I let ReSharper do its thing, the type of the variable will change from DateTime?
to DateTime
.
In fact, let's say that in the remainder of the method, I would use
if (someCondition) dateTimeNullable2 = null;
That would compile just fine, until I let ReSharper replace the second expression with the null coalescing version.
AFAIK, replacing
somevar != null ? somevar : somedefault;
with
somevar ?? somedefault;
should indeed produce the same result. But for implicit typing on a nullable type, the compiler seems to threat ??
as if it means.
somevar != null ? somevar.Value : somedefault;
So I guess my question is why the implicit type is changed when I use ??
, and also where in the documentation I could find info on this.
BTW, this isn't a real world scenario, but I would like to know why using ??
changes the (implicit) type.
Your first two examples are leading you astray; better would be to consider not your
var dateTimeNullable1 = nullableDateTime.HasValue
? nullableDateTime
: DateTime.Now;
but rather
var dateTimeNullable1 = nullableDateTime.HasValue
? nullableDateTime.Value
: DateTime.Now;
To quote section 7.12 "The null coalescing operator" of the C# 3.0 spec (apologies for slightly ropey formatting):
The type of the expression a ?? b
depends on which implicit
conversions are available between the types of the operands. In order
of preference, the type of a ?? b
is A
0
, A
, or B
,
where A
is the type of a
, B
is the type of b
(provided that
b
has a type), and A
0
is the underlying type of A
if
A
is a nullable type, or A
otherwise.
So if a
is Nullable<Something>
, and b
can be implicitly converted to Something
, the type of the whole expression will be Something
. As @Damien_The_Unbeliever suggests, the point of this operator is to coalesce nulls!
To go all language lawyer, for a moment. From the C# spec (version 4):
7.13
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.
So, ??
is explicitly defined to prefer the underlying type of the first expression, if that first expression is a nullable type.
Whereas the language from 7.14 (dealing with ?:
) only discusses the actual types of x
and y
, from the form b ? x : y
, and discusses implicit conversions between these two types.
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
Since Nullable(T)
defines an implicit conversion from T
to Nullable(T)
, and only an explicit conversion from Nullable(T)
to T
, the only possible type of the overall expression is Nullable(T)
.