Неверные типы и тернарный оператор: почему? 10: null` запрещено?

Я натолкнулся на странную ошибку:

private bool GetBoolValue()
{
    //Do some logic and return true or false
}

Затем в другом методе что-то вроде этого:

int? x = GetBoolValue() ? 10 : null;

Простой, если метод возвращает true, назначьте 10 Nullable int x. В противном случае присвойте null тегу nullable. Однако компилятор жалуется:

Ошибка 1 Тип условного выражения не может быть определен, потому что нет никакого неявного преобразования между int и <null>.

Я иду с ума?

Ответы

Ответ 1

Сначала компилятор пытается оценить правильное выражение:

GetBoolValue() ? 10 : null

10 - это буква int (не int?) и null, ну, null. Там нет неявного преобразования между этими двумя, следовательно, сообщение об ошибке.

Если вы измените правое выражение на одно из следующих, то оно скомпилируется, потому что существует неявное преобразование между int? и null (# 1) и между int и int? (# 2, # 3).

GetBoolValue() ? (int?)10 : null    // #1
GetBoolValue() ? 10 : (int?)null    // #2
GetBoolValue() ? 10 : default(int?) // #3

Ответ 2

Попробуйте следующее:

int? x = GetBoolValue() ? 10 : (int?)null;

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

Отбрасывая null на a Nullable<int>, мы явно говорим компилятору, что возвращаемый тип этого выражения должен быть Nullable<int>. Вы могли бы так же легко отличить 10 до int? и иметь тот же эффект.

Ответ 3

Попробуйте следующее:

int? result = condition ? 10 : default(int?);

Ответ 4

Кстати, реализация Microsoft С# -компилятора фактически делает анализ типов условного оператора неправильным в очень тонком и интересном для меня способом. Моя статья о нем Ошибки вывода типа, часть первая.

Ответ 5

Попробуйте выполнить одно из следующих действий:

int? x = GetBoolValue() ? (int?)10 : null;

int? x = GetBoolValue() ? 10 : (int?)null;

Ответ 6

Проблема заключается в том, что тернарный оператор выводит тип, основанный на первом назначении параметра... 10 в этом случае, который является int, а не nullable int.

Вам может быть повезло больше:

int? x = GetBoolValue() (int?)10 : null;

Ответ 7

int? x = GetBoolValue() ? 10 : (int?)null;

Причина, по которой вы видите это, заключается в том, что за кулисами вы используете Nullable, и вам нужно сообщить С#, что ваш "null" является нулевым экземпляром Nullable.

Ответ 8

Просто добавьте эксликс.

int? x = GetBoolValue() ? 10 : (int?)null;

Это тройной оператор, который запутывается - второй аргумент является целым числом, и поэтому третий аргумент рассматривается как целое число, а null не подходит.

Ответ 9

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