Por que isso não compila?
int? number = true ? 5 : null;
O tipo de expressão condicional não pode ser determinado porque não há conversão implícita entre 'int' e <null>
Por que isso não compila?
int? number = true ? 5 : null;
O tipo de expressão condicional não pode ser determinado porque não há conversão implícita entre 'int' e <null>
Respostas:
A especificação (§7.14) diz que para a expressão condicional b ? x : y
, há três possibilidades, tanto x
e y
ambos têm um tipo e certas condições boas são atendidas, apenas um x
e y
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:
Se apenas um de
x
ey
tiver um tipo, e ambosx
ey
forem 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 x
está um int
literal, e y
é o null
que não tem um tipo e null
não é implicitamente conversível em um int
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:
int? number = true ? (int?)5 : null;
Aqui ainda estamos no caso em que apenas um de x
e y
tem um tipo. Observe que null
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 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
x
tem tipoX
ey
tem tipo,Y
então
Se existir uma conversão implícita (§6.1) de
X
paraY
, mas não deY
paraX
, entãoY
é o tipo da expressão condicional.Se existir uma conversão implícita (§6.1) de
Y
paraX
, mas não deX
paraY
, entãoX
é 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 int
e y
é do tipo int?
. Não há conversão implícita de int?
para int
, mas há uma conversão implícita de int
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.
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:
int? number = true ? 5 : (int?)null;
int? number = true ? 5 : null as int?;
int? number = true ? 5 : (int?)null;
e os int? number = true ? (int?)5 : null;
dois compilam !! Scratch, scratch
Como outros já mencionaram, o 5 é um int
e null
nã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>
.
No C# 9
presente é 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;