Compartir a través de


Target-Typed Expresión Condicional

Nota:

Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos y se incorporan en la especificación ECMA actual.

Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.

Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C#, en el artículo sobre especificaciones.

Problema planteado por el experto: https://github.com/dotnet/csharplang/issues/2460

Conversión de expresiones condicionales

Para una expresión condicional c ? e1 : e2, cuando

  1. no existe un tipo común para e1 y e2 o
  2. para la que existe un tipo común pero una de las expresiones e1 o e2 no tiene conversión implícita a ese tipo

definimos una nueva conversión de expresión condicional implícita que permite una conversión implícita de la expresión condicional a cualquier tipo T para la cual existe una conversión desde la expresión de e1 a T, así como de e2 a T. Es un error si una expresión condicional ni tiene un tipo común entre e1 y e2 ni está sujeta a una conversión de expresión condicional.

Mejor conversión a partir de expresión

Cambiamos

Mejor conversión a partir de expresión

Dada una conversión implícita C1 que convierte de una expresión E a un tipo T1y una conversión implícita C2 que convierte de una expresión E a un tipo T2, C1 es una mejor conversión que C2 si E no coincide exactamente con T2 y se cumple al menos una de las siguientes condiciones:

to

Mejor conversión a partir de expresión

Dada una conversión implícita C1 que convierte de una expresión E a un tipo T1y una conversión implícita C2 que convierte de una expresión E a un tipo T2, C1 es una mejor conversión que C2 si E no coincide exactamente con T2 y se cumple al menos una de las siguientes condiciones:

  • E coincide exactamente con T1 (Sección 12.6.4.5)
  • C1 no es una conversión de expresión condicional y C2 es una conversión de expresión condicional.
  • T1 es un destino de conversión mejor que T2 (§12.6.4.7) y tanto C1 como C2 son conversiones de expresión condicional o ninguno es una conversión de expresión condicional.

Expresión de conversión

La especificación actual del lenguaje C# dice

Una cast_expression con el formato (T)E, donde T es un tipo y E es una unary_expression, realiza una conversión explícita (§10.3) del valor de E al tipo T.

En presencia de la conversión de expresión condicional puede haber más de una posible conversión de E a T. Con la adición de la conversión de expresiones condicionales, preferimos cualquier otra conversión a una conversión de expresión condicional y utilizamos la conversión de expresión condicional solo como último recurso.

Notas de diseño

El motivo del cambio a una mejor conversión de la expresión es para manejar un caso como este:

M(b ? 1 : 2);

void M(short);
void M(long);

Este enfoque tiene dos pequeños inconvenientes. En primer lugar, no es exactamente lo mismo que la expresión switch.

M(b ? 1 : 2); // calls M(long)
M(b switch { true => 1, false => 2 }); // calls M(short)

Sigue siendo un cambio de ruptura, pero su alcance es menos probable que afecte a los programas reales:

M(b ? 1 : 2, 1); // calls M(long, long) without this feature; ambiguous with this feature.

M(short, short);
M(long, long);

Esto se vuelve ambiguo porque la conversión a long es mejor para el primer argumento (porque no utiliza la conversión de expresión condicional), pero la conversión a short es mejor para el segundo argumento (porque short es un mejor objetivo de conversión que long). Este cambio rompedor parece menos grave porque no cambia silenciosamente el comportamiento de un programa existente.

El motivo de las notas de la expresión de conversión es manejar un caso como el siguiente:

_ = (short)(b ? 1 : 2);

Este programa utiliza actualmente la conversión explícita de int a short, y queremos preservar el significado lingüístico actual de este programa. El cambio sería inobservable en tiempo de ejecución, pero con el siguiente programa el cambio sería observable:

_ = (A)(b ? c : d);

donde c es de tipo C, d es de tipo D, y hay una conversión implícita definida por el usuario de C a D, y una conversión implícita definida por el usuario de D a A, y una conversión implícita definida por el usuario de C a A. Si este código se compila antes de C# 9.0, cuando b es verdadero, convertimos de c a D y luego a A. Si usamos la conversión de expresiones condicionales, entonces, cuando b es verdadero, convertimos de c a A directamente y ejecutamos una secuencia diferente de código de usuario. Por lo tanto, consideramos la conversión de expresión condicional como último recurso al realizar una conversión, para conservar el comportamiento existente.