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.
Nullable types work as a connector between a database and C# code to provide a way to transform the nulls to be used in C# code. Null Coalescing operators simplify the way to check for nulls and shorten the C# code when the developer is dealing with nulls.
The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null ; otherwise, it evaluates the right-hand operand and returns its result. The ?? operator doesn't evaluate its right-hand operand if the left-hand operand evaluates to non-null.
Boxing a value of a nullable-type produces a null reference if it is the null value (HasValue is false), or the result of unwrapping and boxing the underlying value otherwise. will output the string “Box contains an int” on the console.
You typically use a nullable value type when you need to represent the undefined value of an underlying value type. For example, a Boolean, or bool , variable can only be either true or false . However, in some applications a variable value can be undefined or missing.
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 ofa ?? b
isA
0
,A
, orB
, whereA
is the type ofa
,B
is the type ofb
(provided thatb
has a type), andA
0
is the underlying type ofA
ifA
is a nullable type, orA
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 ofa ?? b
isA0
,A
, orB
, whereA
is the type ofa
(provided thata
has a type),B
is the type ofb
(provided thatb
has a type), andA0
is the underlying type ofA
ifA
is a nullable type, orA
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)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With