Target-Typed Expressão condicional
Observação
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele inclui mudanças de especificação propostas, juntamente com as informações necessárias durante o design e desenvolvimento do recurso. Estes artigos são publicados até que as alterações de especificações propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da Language Design Meeting (LDM).
Você pode saber mais sobre o processo de adoção de especificações de recursos no padrão de linguagem C# no artigo sobre as especificações .
Questão campeã: https://github.com/dotnet/csharplang/issues/2460
Conversão de expressão condicional
Para uma expressão condicional c ? e1 : e2
, quando
- não existe um tipo comum para
e1
ee2
, ou - para o qual existe um tipo comum, mas uma das expressões
e1
oue2
não tem conversão implícita para esse tipo
Definimos um novo de expressão condicional implícita que permite uma conversão implícita da expressão condicional para qualquer tipo T
para o qual exista uma conversão de expressão de e1
para T
e também de e2
para T
. É um erro se uma expressão condicional não tem um tipo comum entre e1
e e2
nem está sujeita a uma conversão de expressão condicional.
Melhor conversão de expressão
Nós mudamos
Melhor conversão a partir da expressão
Dado um
de conversão implícito que converte de um de expressão para um tipo , e um de conversão implícito que converte de um de expressão para um tipo , é um de conversão melhor do que se não corresponder exatamente a e pelo menos uma das seguintes retenções:
Para
Melhor conversão a partir da expressão
Dado um
de conversão implícito que converte de um de expressão para um tipo , e um de conversão implícito que converte de um de expressão para um tipo , é um de conversão melhor do que se não corresponder exatamente a e pelo menos uma das seguintes retenções:
E
corresponde exatamente aoT1
(§12.6.4.5). não é uma de conversão de expressão condicional e é uma conversão de expressão condicional T1
é um alvo de conversão melhor do queT2
(§12.6.4.7) eC1
eC2
são ambos conversões de expressão condicional ou nenhuma é uma conversão de expressão condicional .
Expressão de elenco
A especificação atual da linguagem C# diz
Uma cast_expression da forma
(T)E
, em queT
é um tipo eE
é um unary_expression, executa uma conversão explícita (§10.3) do valor deE
para o tipoT
.
Na presença de uma conversão de expressão condicional , pode haver mais de uma conversão possível de E
para T
. Com a adição da conversão de expressão condicional , preferimos qualquer outra conversão a uma conversão de expressão condicional , e usamos a conversão de expressão condicional apenas como último recurso.
Notas de design
A razão para a mudança para melhor conversão de expressão é lidar com um caso como este:
M(b ? 1 : 2);
void M(short);
void M(long);
Esta abordagem tem duas pequenas desvantagens. Primeiro, não é exatamente o mesmo que a expressão switch:
M(b ? 1 : 2); // calls M(long)
M(b switch { true => 1, false => 2 }); // calls M(short)
Ainda é uma mudança de rutura, mas o seu escopo é menos propenso a afetar programas reais.
M(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous with this feature.
M(short, short);
M(long, long);
Isso se torna ambíguo porque a conversão para long
é melhor para o primeiro argumento (porque não usa a expressão condicional conversão), mas a conversão para short
é melhor para o segundo argumento (porque short
é um alvo de conversão melhor do que long
). Esta mudança de quebra parece menos séria porque não muda silenciosamente o comportamento de um programa existente.
A razão para as notas na expressão "cast" é lidar com um caso como este:
_ = (short)(b ? 1 : 2);
Este programa atualmente usa a conversão explícita de int
para short
, e queremos preservar o significado atual da linguagem deste programa. A mudança seria inobservável em tempo de execução, mas com o seguinte programa a mudança seria observável:
_ = (A)(b ? c : d);
onde c
é do tipo C
, d
é do tipo D
, e há uma conversão implícita definida pelo usuário de C
para D
, e uma conversão implícita definida pelo usuário de D
para A
, e uma conversão implícita definida pelo usuário de C
para A
. Se esse código for compilado antes do C# 9.0, quando b
for verdadeiro, converteremos de c
para D
e, em seguida, para A
. Se usarmos a conversão de expressão condicional, então, quando b
for verdadeira, convertemos de c
para A
diretamente, o que executa uma sequência diferente de código de usuário. Portanto, tratamos a conversão de expressão condicional como um último recurso numa conversão de tipo, para preservar o comportamento existente.
C# feature specifications