Tipos anulables y el operador ternario: ¿por qué es `? 10: nulo` prohibido?

Me encontré con un extraño error:

private bool GetBoolValue() { //Do some logic and return true or false } 

Luego, en otro método, algo como esto:

 int? x = GetBoolValue() ? 10 : null; 

Simple, si el método devuelve verdadero, asigne 10 a Nullable int x. De lo contrario, asigne nulo a la int nullable . Sin embargo, el comstackdor se queja:

Error 1 El tipo de expresión condicional no se puede determinar porque no hay una conversión implícita entre int y .

¿Me estoy volviendo loco?

El comstackdor primero intenta evaluar la expresión de la mano derecha:

 GetBoolValue() ? 10 : null 

El 10 es un int literal (no int? ) Y null es, bueno, null . No hay conversión implícita entre esos dos, por lo tanto, el mensaje de error.

Si cambia la expresión de la mano derecha a uno de los siguientes, ¿comstack porque hay una conversión implícita entre int? y null (# 1) y entre int e int? (# 2, # 3).

 GetBoolValue() ? (int?)10 : null // #1 GetBoolValue() ? 10 : (int?)null // #2 GetBoolValue() ? 10 : default(int?) // #3 

Prueba esto:

 int? x = GetBoolValue() ? 10 : (int?)null; 

Básicamente, lo que está sucediendo es que el operador condicional no puede determinar el “tipo de retorno” de la expresión. Dado que el comstackdor decide implícitamente que 10 es una int , entonces decide que el tipo de retorno de esta expresión también será un int . Como un int no puede ser null (el tercer operando del operador condicional) se queja.

Al Nullable el null en Nullable le estamos diciendo explícitamente al comstackdor que el tipo de retorno de esta expresión será un Nullable . ¿Podrías haber lanzado tan fácilmente el 10 a int? también y tuvo el mismo efecto.

Prueba esto:

int? result = condition ? 10 : default(int?);

A propósito, la implementación de Microsoft del comstackdor de C # realmente hace que el análisis de tipo del operador condicional sea incorrecto de una manera muy sutil e interesante (para mí). Mi artículo sobre esto es problemas de inferencia de tipo, primera parte .

Pruebe uno de estos:

 int? x = GetBoolValue() ? (int?)10 : null; int? x = GetBoolValue() ? 10 : (int?)null; 

El problema es que el operador ternario está deduciendo el tipo basado en su primera asignación de parámetro … 10 en este caso, que es un int, no un nulo nulo.

Puede que tengas mejor suerte con:

 int? x = GetBoolValue() (int?)10 : null; 
 int? x = GetBoolValue() ? 10 : (int?)null; 

La razón por la que ve esto es porque detrás de las escenas está usando Nullable y necesita decirle a C # que su “nulo” es una instancia nula de Nullable.

Solo agrega un lanzamiento explicto.

 int? x = GetBoolValue() ? 10 : (int?)null; 

Es el operador ternario el que se confunde: el segundo argumento es un número entero, por lo que también se espera que el tercer argumento sea un número entero y nulo no encaje.

Es porque el comstackdor determina el tipo de operador condicional por su segundo y tercer operando, no por lo que le asigna el resultado. No hay conversión directa entre un entero y una referencia nula que el comstackdor puede usar para determinar el tipo.