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

Условный оператор?: С отличным типом

Из документации MSDN следующие два фрагмента равны:

bool value;
int x = (value) ? 0 : 1;

и

bool value;
int x;
if (value)
    x = 0;
else
    x = 1;

Отличный, замечательный. Я использую это все время. Тесный и эффективный.

Если мы попробуем это с нулевым типом, например:

int? x = (value.HasValue) ? value.Value : null;

Мы получаем ошибку времени компиляции:

The type of conditional expression cannot be determined
because there is no implicit conversion between '{NullableType}' and null.

Это компилируется отлично:

int? value;
int? x;

if (value.HasValue)
    x = value.Value;
else
    x = null;

Итак, я понимаю, что для компиляции первого оператора компилятор требует явного перевода на (int?)null. Я не понимаю, почему это требуется в этом выражении, но не в блоке If Else.

4b9b3361

Ответ 1

null может представлять любой тип данных на основе объектов. Вам нужно указать null как тип данных, чтобы он знал, о чем вы говорите.

int? x = (value.HasValue) ? value.Value : (int?)null;

Я знаю, это звучит немного странно.


Чтобы ответить на вопросы в комментариях:

Почему это не подразумевается, хотя?
Да, я понимаю. Но почему мне не нужно бросать его в блок If Else?

Пропустить через код.

Ваш оператор else выглядит следующим образом:

else x = null;

Это означает, что вы назначаете значение null на x. Это справедливо, поскольку x является int?, который принимает nulls.

Разница возникает, когда у вас есть тернарный оператор. В нем говорится: "присвойте значение оператора в x". Вопрос (и причина вашей ошибки) заключается в том, какой тип данных является результатом тернарного оператора?

Из вашего кода вы не можете быть уверены, и компилятор поднимает руки вверх.

int? x = (value.HasValue) ? value.Value : null;
// int?        bool             int        ??

Какой тип данных null? Вы быстро можете сказать "хорошо это a int?, потому что другая сторона - это int, а результат - int?". Проблема заключается в следующем:

string a = null;
bool? b = null;
SqlConnectionStringBuilder s = null;

Это также верно, что означает, что null можно использовать для any object-based datatype. Вот почему вы должны явно использовать null как тип, который хотите использовать, потому что он может быть использован для чего угодно!


Другое объяснение (и возможно более точное):

Вы не можете иметь неявный бросок между значением NULL и значением, отличным от нуля.

int не является нулевым (это структура), где null is. Вот почему в ответе Хабиба вы можете поставить бросок на левую или правую сторону.

Ответ 2

Для Конд. оператор MSDN:

Любой тип выражения first_expression и second_expression должен быть то же или неявное преобразование должно существовать от одного типа до другой.

Итак, в вашем случае ваше первое выражение и второе выражение:

int? x = (value.HasValue) ? value.Value : null;
                             ^^^^^^^^      ^^^^^
                             first exp     2nd Exp

Теперь, если вы видите, ваше первое выражение имеет тип int, а второе выражение null, и оба они не одинаковы, и нет никакого неявного преобразования. Итак, кастинг любого из них на `int? решает проблему.

Итак:

int? x = (value.HasValue) ? (int?) value.Value : null;

или

int? x = (value.HasValue) ? value.Value : (int?) null;

в порядке.

Теперь почему это не требуется с if-else, потому что здесь задействовано несколько операторов, и это не один оператор, присваивающий значение.

Ответ 3

var x = value.HasValue ? value.Value : default(int?);

работает тоже.

Ответ 4

Документация для оператора?: указывает, что тип выражения b? x: y определяется путем изучения типов x и y:

  • Если X и Y являются одним и тем же типом, то это тип условного выражения.
  • В противном случае, если неявное преобразование (раздел 6.1) существует от X до Y, но не от Y до X, то Y является типом условного выражения.
  • В противном случае, если неявное преобразование (раздел 6.1) существует от Y до X, но не от X до Y, тогда X является типом условного выражения.
  • В противном случае тип выражения не может быть определен, и возникает ошибка времени компиляции.

В вашем примере

int? x = (value.HasValue) ? value.Value : null;

нет никакого неявного преобразования между int и null, поэтому применяется последняя марка.

Ответ 5

Причина в том, что тип условного выражения определяется вторым и третьим операторами условного оператора (?:).

Так как null не имеет типа, компилятор не может определить тип общего выражения, поэтому он испускает ошибку компилятора.

Причина, по которой он работает с простым оператором присваивания (=), состоит в том, что левая часть оператора определяет тип. Поскольку в инструкции If тип x уже известен, компилятор не жалуется.

Дополнительные пояснения см. в разделе 7.14 (Условный оператор) и разделе 7.17.1 (Простое назначение).