Partilhar via


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

  1. não existe um tipo comum para e1 e e2, ou
  2. para o qual existe um tipo comum, mas uma das expressões e1 ou e2 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:

  • E corresponde exatamente ao T1 (§12.6.4.5)
  • T1 é uma meta de conversão melhor do que T2 (§12.6.4.7)

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 ao T1 (§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 que T2 (§12.6.4.7) e C1 e C2 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 que T é um tipo e E é um unary_expression, executa uma conversão explícita (§10.3) do valor de E para o tipo T.

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.