Подтвердить что ты не робот

Использование коалесцирующего оператора null в типах с нулевым типом изменяет неявный тип

Я ожидал бы, что следующие три строки кода будут одинаковыми:

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;
}

Во всех случаях я назначаю nullableDateTime новой переменной. Я бы ожидал, что тип всех переменных станет DateTime?, так как это тип nullableDateTime. Но, к моему удивлению, тип dateTimeWhatType просто становится DateTime, поэтому не имеет значения NULL.

Чтобы ухудшить ситуацию, ReSharper предлагает заменить второй оператор нулевым коалесцирующим выражением, превратив его в выражение 3. Поэтому, если я позволю ReSharper делать свое дело, тип переменной изменится с DateTime? на DateTime.

Действительно, скажем, что в оставшейся части метода я использовал бы

if (someCondition) dateTimeNullable2 = null;

Это будет компилироваться просто отлично, пока я не позволю ReSharper заменить второе выражение на нулевую коалесцирующую версию.

AFAIK, заменив

somevar != null ? somevar : somedefault;

с

somevar ?? somedefault;

действительно должен дать тот же результат. Но для неявной типизации для типа с нулевым значением компилятор кажется угрозой ??, как будто это означает.

somevar != null ? somevar.Value : somedefault;

Итак, я думаю, мой вопрос в том, почему неявный тип изменяется, когда я использую ??, а также где в документации я мог найти информацию об этом.

Кстати, это не сценарий реального мира, но я хотел бы знать, почему использование ?? изменяет (неявный) тип.

4b9b3361

Ответ 1

Ваши первые два примера приводят вас в заблуждение; лучше было бы рассмотреть не ваш

var dateTimeNullable1 = nullableDateTime.HasValue 
    ? nullableDateTime 
    : DateTime.Now;

а скорее

var dateTimeNullable1 = nullableDateTime.HasValue 
    ? nullableDateTime.Value 
    : DateTime.Now;

Чтобы процитировать раздел 7.12 "Нулевой коалесцирующий оператор" спецификации С# 3.0 (извинения за слегка роути-форматирование):

Тип выражения a ?? b зависит от того, какой неявный между типами операндов доступны преобразования. В порядке предпочтительным типом a ?? b является A 0, A или B, где A - тип A, B - тип B (при условии, что B имеет тип), а A 0 является базовым типом A, если A - тип с нулевым значением или A в противном случае.

Итак, если A - Nullable<Something>, а B может быть неявно преобразовано в Something, тип всего выражения будет Something. Как предлагает @Damien_The_Unbeliever, точкой этого оператора является объединение значений нуля!

Ответ 2

На все языки должен пройти весь юридический адвокат. Из спецификации С# (версия 4):

7,13

Тип выражения a ?? b зависит от того, какие неявные преобразования доступны в операндах. В порядке предпочтения тип a ?? b равен A0, A или B, где A - тип A (при условии, что A имеет тип), B является типом B (при условии, что B имеет тип), а A0 является базовым типом A, если A - тип с нулевым значением, или A в противном случае.

Итак, ?? явно определен, чтобы предпочесть базовый тип первого выражения, если это первое выражение является нулевым типом.

В то время как язык 7.14 (имеющий дело с ?:) обсуждает фактические типы x и y, из формы b ? x : y, и обсуждает неявные преобразования между этими двумя типы.

Если неявное преобразование (§6.1) существует от X до Y, но не от Y до X, то Y является типом условного выражения

Так как Nullable(T) определяет неявное преобразование из T в Nullable(T), и только явное преобразование из Nullable(T) в T, единственным возможным типом общего выражения является Nullable(T).