using coalescing null operator on nullable types c

2019-02-21 08:59发布

问题:

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.

回答1:

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 A0, A, or B, where A is the type of a, 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 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!



回答2:

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