Использование коалесцирующего оператора 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;
Итак, я думаю, мой вопрос в том, почему неявный тип изменяется, когда я использую ??
, а также где в документации я мог найти информацию об этом.
Кстати, это не сценарий реального мира, но я хотел бы знать, почему использование ??
изменяет (неявный) тип.
Ответы
Ответ 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)
.