tipo puede parse net implícitamente convertir como asp arreglo c# ternary-operator casting boolean-expression

parse - no se puede convertir de ''string'' a ''int'' c#



¿Por qué tengo que convertir un int en una expresión ternaria? (4)

Posible duplicado:
El operador condicional no puede transmitir implícitamente?

Me encontré con una situación peculiar y quiero saber por qué tengo que hacerlo. Estoy usando .NET 3.5.

Esto funciona:

short foo; if (isValid) foo = -1; else foo = getFoo();

Esto no funciona:

short foo; foo = isValid ? -1 : getFoo();

Tengo que encasillar -1:

short foo; foo = isValid ? (short)-1 : getFoo();

¿Qué hace la expresión ternaria de manera diferente? Considera que -1 es una int que necesita ser convertida en un corto. ¿Pero por qué?


El operador condicional impone que ambas expresiones de resultados posibles sean del mismo tipo. En este caso, el lado izquierdo es un int y el lado derecho es un short devuelto por el método getPoo . Como siempre es seguro convertir un short en int el compilador elige que el resultado de la operación será un int .

Por lo tanto, el resultado será la asignación de un int a un short y es por eso que debe lanzarlo explícitamente a un corto.

Si utiliza explícitamente un enfoque if / else, asignará un entero literal a un corto que le permita al compilador verificar que el entero literal esté asignado de manera segura a un corto sin la necesidad de un molde explícito.

Para una explicación interna, eche un vistazo a:

Los operadores de elenco no obedecen la ley distributiva


Porque -1 por defecto es un número entero. Es mucho más seguro para el compilador decirte que tienes que decirle explícitamente qué hacer, que el compilador debe asumir lo que quieres que se haga.

Tu ejemplo es bastante directo. Con un poco de trabajo extra, el compilador podría ver que quiere que -1 sea corto. Hay todos los casos extremos que van junto con la conversión implícita que no son tan simples sin embargo. Si agrega una regla para que el compilador asuma lo que desea, debe aplicarla en todos los casos, no solo en uno, y allí es donde se dificulta.

Como nota, deberías consultar el blog de Eric Lippert, ya que sé que él explica por qué el compilador no hace tales suposiciones.


Un operador condicional aplicado a un int y un short es de tipo int ; el compilador no deducirá el tipo de expresión del tipo al que lo asigne.

No puede convertir implícitamente esta short expresión en int .


Unas pocas cosas.

En primer lugar, el operador condicional es un operador ternario, no un operador terciario .

En segundo lugar, observo que en las muestras de código, las dos muestras de código que se pretende que sean equivalentes no son:

short foo; if (isValid) foo = -1; else getFoo();

no es lo mismo que

short foo = isValid ? (short)-1 : getFoo();

El primero deja foo sin asignar si isValid es falso. Este último asigna foo independientemente del valor de isValid.

Supongo que querías decir

short foo; if (isValid) foo = -1; else foo = getFoo();

y que, además, getFoo () vuelve corto.

La pregunta es por qué la conversión en el operador condicional sin el tipo de conversión es ilegal, pero como consecuencia de la declaración if es legal.

Es legal en la declaración if porque la sección 6.1.9 de la especificación establece:

Una expresión constante de tipo int se puede convertir a tipo sbyte, byte, short, ushort, uint o ulong, siempre que el valor de la expresión constante esté dentro del rango del tipo de destino.

-1 es una expresión constante de tipo int que está en el rango de corto, por lo que se puede convertir a corto implícitamente.

Entonces, ¿por qué la expresión condicional es falsa?

Lo primero que tenemos que establecer claramente es la regla de que el tipo de expresión condicional se determina a partir de su contenido , no de su contexto . ¡El tipo de expresión en el lado derecho de una tarea no depende de lo que se le asigna! Supongamos que tienes

short M(short x){...} int M(int x){...} short y = M(-1);

No creo que espere una resolución de sobrecarga para decir "bueno, normalmente elegiría M (int) porque -1 es un int, pero no, escogeré M (corto) en su lugar porque de lo contrario la tarea ganó '' t trabajo ". La resolución de sobrecarga no sabe nada sobre hacia dónde va el resultado . Su trabajo es determinar cuál es la sobrecarga correcta basada en los argumentos dados, no en función del contexto de la llamada.

La determinación del tipo de expresión condicional funciona de la misma manera. No miramos el tipo al que va, miramos los tipos que están en la expresión.

De acuerdo, entonces hemos establecido que el hecho de que esto esté siendo asignado a corto es irrelevante para determinar el tipo de expresión. Pero eso aún deja la pregunta "¿Por qué el tipo de la expresión condicional es int en lugar de corto?"

Esa es una muy buena pregunta. Vamos a la especificación.

El segundo y tercer operandos, xey, del operador?: Controlan el tipo de expresión condicional.

Si tiene tipo X e y tiene tipo Y, entonces:

Si existe una conversión implícita de X a Y, pero no de Y a X, entonces Y es el tipo de expresión condicional.

Si existe una conversión implícita 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 este caso, los operandos tienen un tipo. (La verborrea allí acerca de "si x tiene un tipo ..." es para el caso donde tienes nulo o una lambda allí, ¡aquellos que no tienen tipos!) El primer operando es de tipo int, el segundo es de tipo corto.

Existe una conversión implícita de corto a int, pero no de int a corto. Por lo tanto, el tipo de expresión condicional es int, que no puede asignarse a short.

Ahora, uno podría decir que este algoritmo no es tan bueno como podría ser. Podríamos complicar enormemente el algoritmo para tratar todos los casos en los que había dos tipos posibles "candidatos"; en este caso, int y short son candidatos plausibles porque ambas ramas son convertibles a int y short cuando se consideran expresiones específicas. en lugar de simplemente tener tipos . Podríamos decir en ese caso que el tipo más pequeño es el más pequeño .

(A veces en C # decimos que el tipo más general de dos tipos es el mejor, pero en este caso querría que escogiéramos el más específico. El lenguaje no es consistente en este aspecto particular del diseño, desafortunadamente, yo personalmente preferiría que siempre elija el más específico, pero hay escenarios de inferencia de tipo en los que eso sería un cambio radical ahora).

Consideré hacer eso en 2006. Al diseñar el comportamiento de cómo LINQ lidia con situaciones donde hay varios tipos para elegir y uno debe ser escogido como "el mejor" notamos que el operador condicional ya tenía que resolver este problema, y que además, en C # 2 no se implementó realmente de acuerdo con las especificaciones. Hubo un largo debate sobre esto y terminamos haciendo algunos cambios menores a la especificación para que el operador condicional lo alinee más con su comportamiento implementado (y deseado). Sin embargo, decidimos no tomar el mayor cambio de última hora de ajustar el algoritmo para usar el menor de dos tipos posibles cuando había varios para elegir.

Para algunas reflexiones sobre este problema, vea mis publicaciones de 2006 en él: