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 nullainda 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.
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:
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:newint?();int? num =true?5:nullasint?;int? num =true?5:(int?)null;int? num =true?(int?)5:null;int? num =true?5asint?:null;int? num =true?newint?(5):null;
Além disso, em qualquer lugar que você ver int?, você também pode usar Nullable<int>.
À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 typeint? result = b ?0:null;// nullable value type
Respostas:
A especificação (§7.14) diz que para a expressão condicional
b ? x : y
, há três possibilidades, tantox
ey
ambos têm um tipo e certas condições boas são atendidas, apenas umx
ey
tem 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:
A questão aqui é que, em
apenas um dos resultados condicionais tem um tipo. Aqui
x
está umint
literal, ey
é onull
que não tem um tipo enull
não é implicitamente conversível em umint
1 . 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:
Aqui ainda estamos no caso em que apenas um de
x
ey
tem um tipo. Observe quenull
ainda não possui um tipo, o compilador não terá nenhum problema com isso, porque(int?)5
enull
são ambos implicitamente conversível paraint?
(§6.1.4 e §6.1.5).A outra maneira é obviamente:
mas agora precisamos ler uma cláusula diferente na especificação para entender por que isso está correto:
Aqui
x
é do tipoint
ey
é do tipoint?
. Não há conversão implícita deint?
paraint
, mas há uma conversão implícita deint
paraint?
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.
fonte
new int?()
no lugar de(int?)null
.DateTime
, quando de facto necessário(DateTime?)
null
não tem nenhum tipo identificável - ele só precisa de um pouco de estímulo para torná-lo feliz:fonte
int? number = true ? 5 : null as int?;
null
não tenha um tipo identificável. O problema é que não há conversão implícita denull
paraint
. Detalhes aqui .int? number = true ? 5 : (int?)null;
e osint? number = true ? (int?)5 : null;
dois compilam !! Scratch, scratchComo outros já mencionaram, o 5 é um
int
enull
não pode ser implicitamente convertido emint
.Aqui estão outras maneiras de solucionar o problema:
Além disso, em qualquer lugar que você ver
int?
, você também pode usarNullable<int>
.fonte
No
C# 9
presente é agora permitido blogueOu seu exemplo:
fonte