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

167

Почему это не компилируется?

int? number = true ? 5 : null;

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

davidhq
источник

Ответы:

341

Спецификация (§7.14) гласит, что для условного выражения b ? x : yсуществует три возможности, xи yоба имеют тип и выполняются определенные хорошие условия , только один из xи yимеет тип, и определенные хорошие условия выполняются, или ошибка времени компиляции происходит. Здесь «определенные хорошие условия» означают, что возможны определенные преобразования, о которых мы поговорим ниже.

Теперь давайте обратимся к немецкой части спецификации:

Если только один из xи yимеет тип, и оба, xи yнеявно преобразуются в этот тип, то это тип условного выражения.

Проблема здесь в том, что в

int? number = true ? 5 : null;

только один из условных результатов имеет тип. Вот xэто intбуквально, и yэто nullкоторый не не имеют типа и nullне неявно раскладывается в int1 . Следовательно, «определенные хорошие условия» не выполняются, и возникает ошибка времени компиляции.

Там являются два пути вокруг этого:

int? number = true ? (int?)5 : null;

Здесь мы все еще в случае, когда только один из xи yимеет тип. Обратите внимание , что до null сих пор не имеет типа пока компилятор не будет иметь никаких проблем с этим , потому что (int?)5и nullоба неявно преобразованы в int?(§6.1.4 и §6.1.5).

Другой способ, очевидно,

int? number = true ? 5 : (int?)null;

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

Если xимеет тип Xи yимеет тип, Yто

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

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

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

Вот xтипа intи yтипа int?. Там нет неявного преобразования int?к int, но есть неявное преобразование intк int?такому типу выражения int?.

1 : Отметим далее, что тип левой части игнорируется при определении типа условного выражения, что является распространенным источником путаницы.

Ясон
источник
4
Хорошая цитата из спецификации, чтобы проиллюстрировать, почему это происходит - +1!
JerKimball
8
Другой вариант new int?()на месте (int?)null.
Гуванте
1
Это также относится к случаю, если у вас есть тип поля базы данных, обнуляемый обнуляемым значением, например, обнуляемый тип DateTime, и вы пытаетесь привести данные к ним DateTime, когда это потребуется,(DateTime?)
Майк Апджон,
73

null не имеет идентифицируемого типа - просто нужно немного подтолкнуть его, чтобы сделать его счастливым:

int? number = true ? 5 : (int?)null;
Марк Гравелл
источник
3
Или вы можете сделатьint? number = true ? 5 : null as int?;
Брэд М
Хороший ответ на вопрос. Хорошее связанное чтение: ericlippert.com/2013/05/30/what-the-meaning-of-is-is
Бенджамин Грюнбаум
Проблема не в том, nullчто не имеет идентифицируемого типа. Проблема в том, что нет неявного преобразования из nullв int. Подробности здесь .
Джейсон
Интересно то, что int? number = true ? 5 : (int?)null;и int? number = true ? (int?)5 : null;как компиляции !! Царапина, царапина
davidhq
2
Я объясняю точно, почему это происходит в моем ответе .
Джейсон
4

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

Вот другие способы обойти эту проблему:

int? num = true ? 5 : default(int?);
int? num = true ? 5 : new int?();

int? num = true ? 5 : null as int?;
int? num = true ? 5 : (int?)null;

int? num = true ? (int?)5 : null;
int? num = true ? 5 as int? : null;

int? num = true ? new int?(5) : null;

Кроме того, везде, где вы видите int?, вы также можете использовать Nullable<int>.

Андрей
источник
1

В C# 9этом сейчас разрешен блог

Цель набрана ?? и ?

Иногда условно и?: выражения не имеют очевидного общего типа между ветвями. Такие случаи сегодня терпят неудачу, но C # 9.0 разрешит их, если есть целевой тип, в который преобразуются обе ветви:

Person person = student ?? customer; // Shared base type
int? result = b ? 0 : null; // nullable value type

Или ваш пример:

// Allowed in C# 9.
int? number = true ? 5 : null;
WBuck
источник