O tipo de expressão condicional não pode ser determinado porque não há conversão implícita entre 'int' e <null>

Respostas:

338

A especificação (§7.14) diz que para a expressão condicional b ? x : y, há três possibilidades, tanto xe yambos têm um tipo e certas condições boas são atendidas, apenas um xe ytem um tipo e certa condições boas são cumpridos, ou um erro de tempo de compilação ocorre. Aqui, "certas boas condições" significa que certas conversões são possíveis, as quais entraremos em detalhes abaixo.

Agora, passemos à parte pertinente da especificação:

Se apenas um de xe ytiver um tipo, e ambos xe yforem implicitamente conversíveis nesse tipo, esse é o tipo da expressão condicional.

A questão aqui é que, em

int? number = true ? 5 : null;

apenas um dos resultados condicionais tem um tipo. Aqui xestá um intliteral, e yé o nullque não tem um tipo e nullnão é implicitamente conversível em um int1 . Portanto, "certas boas condições" não são atendidas e ocorre um erro em tempo de compilação.

Não são duas maneiras de contornar isso:

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

Aqui ainda estamos no caso em que apenas um de xe ytem um tipo. Observe que null ainda não possui um tipo, o compilador não terá nenhum problema com isso, porque (int?)5enull são ambos implicitamente conversível para int?(§6.1.4 e §6.1.5).

A outra maneira é obviamente:

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

mas agora precisamos ler uma cláusula diferente na especificação para entender por que isso está correto:

Se xtem tipo Xe ytem tipo, Yentão

  • Se existir uma conversão implícita (§6.1) de Xpara Y, mas não de Ypara X, então Yé o tipo da expressão condicional.

  • Se existir uma conversão implícita (§6.1) de Ypara X, mas não de Xpara Y, então Xé o tipo da expressão condicional.

  • Caso contrário, nenhum tipo de expressão poderá ser determinado e ocorrerá um erro em tempo de compilação.

Aqui xé do tipo inte yé do tipo int?. Não há conversão implícita de int?para int, mas há uma conversão implícita de intparaint? portanto o tipo da expressão é int?.

1 : Observe ainda que o tipo do lado esquerdo é ignorado na determinação do tipo da expressão condicional, uma fonte comum de confusão aqui.

Jason
fonte
4
Boa citação das especificações para ilustrar por que isso acontece - +1!
precisa saber é o seguinte
7
Outra opção está new int?()no lugar de (int?)null.
Guvante
1
Este também é o caso, se você tem um tipo de campo de banco de dados anulável, por exemplo, um DateTime anulável e você tentar e dados elenco para DateTime, quando de facto necessário(DateTime?)
Mike Upjohn
73

null não tem nenhum tipo identificável - ele só precisa de um pouco de estímulo para torná-lo feliz:

int? number = true ? 5 : (int?)null;
Marc Gravell
fonte
2
Ou você pode fazerint? number = true ? 5 : null as int?;
Brad M
Boa resposta acertando o ponto. Boa leitura relacionada: ericlippert.com/2013/05/30/what-the-meaning-of-is-is
Benjamin Gruenbaum
O problema não é que nullnão tenha um tipo identificável. O problema é que não há conversão implícita de nullpara int. Detalhes aqui .
jason
o interessante é que int? number = true ? 5 : (int?)null;e os int? number = true ? (int?)5 : null;dois compilam !! Scratch, scratch
davidhq 15/08
2
Eu cubro exatamente por que isso acontece na minha resposta .
jason
4

Como outros já mencionaram, o 5 é um inte nullnão pode ser implicitamente convertido em int.

Aqui estão outras maneiras de solucionar o problema:

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;

Além disso, em qualquer lugar que você ver int?, você também pode usar Nullable<int>.

Andrew
fonte
1

No C# 9presente é agora permitido blogue

Alvo digitado ?? e?

Às vezes condicional ?? e?: as expressões não têm um tipo compartilhado óbvio entre os ramos. Esses casos falham hoje, mas o C # 9.0 os permitirá se houver um tipo de destino para o qual os dois ramos se convertam:

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

Ou seu exemplo:

// Allowed in C# 9.
int? number = true ? 5 : null;
WBuck
fonte