2010-04-09 11 views
21

El siguiente código no se compila:¿Por qué null necesita un molde de tipo explícito aquí?

//int a = ... 
int? b = (int?) (a != 0 ? a : null); 

Para compilar, lo que debe ser cambiado a

int? b = (a != 0 ? a : (int?) null); 

Dado que tanto b = null y b = a son legales, esto no tiene sentido para mí .

¿Por qué tenemos que convertir el null en un int? y por qué no podemos simplemente proporcionar un molde de tipo explícito para toda la expresión (que sé que es posible en otros casos)?

+8

Creo que al compilador no le gusta que haga tantas preguntas. Quiero decir, ¡mira, tienes 3 de ellos en una sola línea! – David

+2

Esto debería responder a su pregunta de por qué: http://stackoverflow.com/questions/2215745/conditional-operator-cannot-cast-implicitly/2215959#2215959. Esta pregunta no es * exactamente * un duplicado de eso, pero el razonamiento sigue siendo el mismo. –

+1

Tenga en cuenta que 'int? b = a! = 0? (int?) a: null; 'también funciona –

Respuesta

18

Desde el capítulo 7.13 de la Especificación del lenguaje C#:

El segundo y tercer operandos de la:? El control del operador del tipo de la expresión condicional. Deje que X e Y sean los tipos del segundo y tercer operandos. Luego,

  • Si X e Y son del mismo tipo, este es el tipo de expresión condicional.
  • De lo contrario, si existe una conversión implícita (§6.1) de X a Y, pero no de Y a X, entonces Y es el tipo de expresión condicional.
  • De lo contrario, si existe una conversión implícita (§6.1) de Y a X, pero no de X a Y, entonces X es el tipo de expresión condicional.
  • De lo contrario, no se puede determinar ningún tipo de expresión y se produce un error en tiempo de compilación.

En su caso, no hay conversión implícita de int a nulo, ni a la inversa. Su yeso resuelve el problema, int es convertible a int?

+0

Ah, ya veo. Sin embargo, no creo que las dos expresiones deban tener el mismo tipo, siempre y cuando ambas incluyan implícitamente el tipo asignado, ¿qué ocurre si digo 'animal animal = (condición? Nuevo gato(): nuevo perro ()) ' –

+1

Luego también obtendrá un error de compilación. (A menos que arroje cualquier lado a 'Animal') – SLaks

+1

El lado izquierdo de la declaración de asignación no afecta el tipo de la expresión. Los gatos no son implícitamente convertibles en perros, insiste mi esposa. –

1

es porque cuando utiliza ese tipo de notación, ambos miembros deben ser del mismo tipo, por lo que debe decir explícitamente "¿este miembro es un int?".

¿Está claro?

+0

-1: no es necesario que sean del mismo tipo, uno solo necesita ser convertible al tipo del otro: ver más arriba, @nobugz y @Vlad. – ANeves

+0

@srpt, yo también quería votar, pero luego vi que realmente no bajaste ni deshiciste mi voto negativo. –

+0

=/I qué? * [monóculo salta] * ¡Maldiciones! Deshice el downvote porque cambié de opinión, pero olvidé editar '-1:' al comienzo del comentario, ¡perdón! (Cambié de opinión porque no es una respuesta incorrecta, simplemente no es muy precisa o clara.) – ANeves

5

Las dos alternativas del operador ?: deben ser del mismo tipo. De lo contrario, el compilador no puede deducir el tipo de expresión condicional completa.

null no es un int, por lo que debe dar una pista al compilador de que el tipo resultante es int?.


Editar: como los otros señalaron, los dos tipos no tienen que ser los mismos, pero uno de ellos debe ser convertible a otro (que otro será el tipo de resultado). Ver specs para más detalles.

1

Cuando utiliza el operador condicional con operandos de diferentes tipos, el compilador comprobará si uno de los tipos se puede convertir implícitamente al otro tipo.

Si ningún tipo se puede convertir implícitamente al otro, dará un error, incluso si hay un tercer tipo al que ambos pueden convertir implícitamente. El compilador no insertará una conversión implícita en ambos lados a la vez.

En su caso, tanto int como null requieren conversiones implícitas para convertirse en int?, por lo que no funciona.
Necesita cambiar su código para que un lado sea int? y el otro lado se pueda convertir implícitamente a int?. La forma simplested de hacer esto es para reemplazar null con new int?(), así:

int? b = (a != 0 ? a : new int?()); 

Esto sólo requiere una conversión implícita (int a int?).

5

Puede evitar el lanzamiento si utiliza default(int?) en lugar de null.

int a = 42; 
int? b = (a != 0 ? a : default(int?)); 
0

Esto es más o menos un duplicado de one de mis preguntas, en relación con el operador condicional. No es el nulo, realmente es el :.

La respuesta aceptada es bastante buena, de nada menos que Eric Lippert, que está en el equipo compilador de C#.

Cuestiones relacionadas