2010-02-07 43 views
53

estoy un poco perplejo por este pequeño C# peculiaridad:¿El operador condicional no puede transmitir implícitamente?

las variables dado:

Boolean aBoolValue; 
Byte aByteValue; 

Los siguientes compilaciones:

if (aBoolValue) 
    aByteValue = 1; 
else 
    aByteValue = 0; 

Pero esto no:

aByteValue = aBoolValue ? 1 : 0; 

El error dice: "No se puede convertir implícitamente el tipo 'int' a 'byte'."

Y, por supuesto, esta monstruosidad compilará:

aByteValue = aBoolValue ? (byte)1 : (byte)0; 

¿Qué está pasando aquí?

EDIT:

Usando VS2008, C# 3.5

+0

posible duplicado de [Tipos anulables y el operador ternario: ¿por qué es \ '? 10: null \ 'prohibited?] (Http://stackoverflow.com/questions/858080/nullable-types-and-the-ternary-operator-why-is-10-null-forbidden) – nawfal

Respuesta

62

Esta es una pregunta bastante frecuente.

En C#, casi siempre razonamos desde adentro hacia afuera. Cuando vea

x = y; 

trabajamos lo que es el tipo de x, ¿cuál es el tipo de y, y si el tipo de y es compatible con la asignación x. Pero no usamos el hecho de que sabemos cuál es el tipo de x cuando estamos trabajando en el tipo de y.

Eso es porque puede haber más de una x:

void M(int x) { } 
void M(string x) { } 
... 
M(y); // y is assigned to either int x or string x depending on the type of y 

Nos necesidad de ser capaz de trabajar a cabo el tipo de una expresión sin saber lo que está siendo asignado a.Escriba flujos de información de una expresión, no en una expresión.

Para calcular el tipo de expresión condicional, calculamos el tipo de consecuencia y las expresiones alternativas, seleccionamos el más general de los dos tipos, y eso se convierte en el tipo de expresión condicional. Entonces en su ejemplo, el tipo de expresión condicional es "int", y no es una constante (a menos que la expresión de condición sea constante verdadera o constante). Como no es una constante, no puedes asignarla a byte; el compilador solo razona de los tipos, no de los valores, cuando el resultado no es una constante.

La excepción a todas estas reglas son las expresiones lambda, donde la información de tipo hace fluir del contexto a la lambda. Conseguir esa lógica correcta fue muy difícil.

+2

Mi mente está impresa . Gracias, señor, es una parte esclarecedora y dos partes frustrante. Una porque no puede funcionar de la manera que * parece * funcionar, y dos porque tiene sentido que no pueda funcionar de esa manera. Entonces ... ¡constantes! – MPelletier

+0

Gracias. Estaba buscando una publicación sobre este tema en tu blog, pero esto es aún mejor. –

+0

@John: hablo de estos temas un poco aquí: http://blogs.msdn.com/ericlippert/archive/2006/05/24/type-inference-woes-part-one.aspx –

5

Puede que no tenga una gran respuesta para ti, pero si lo hace en muchos lugares, se podría declarar:

private static readonly Byte valueZero = (byte)0; 
private static readonly Byte valueOne = (byte)1; 

y solo estas variables. Puede salirse con la suya usando const si es local para el proyecto.

EDIT: usando readonly no tendría sentido - éstos no están destinados a cambiar nunca.

+0

Estoy seguro de que fue solo un error tipográfico, pero usted declaró la misma variable dos veces. –

+1

@Hamish: entiendo a qué te refieres. Podría usar const, pero es una solución. Sin duda, esto no merece el voto negativo. – MPelletier

9

estoy usando VS 2005, para que pueda reproducirse y, por bool & de Boole, pero no por cierto

bool abool = true; 
Boolean aboolean = true; 
Byte by1 = (abool ? 1 : 2); //Cannot implicitly convert type 'int' to 'byte' 
Byte by2 = (aboolean ? 1 : 2); //Cannot implicitly convert type 'int' to 'byte' 
Byte by3 = (true ? 1 : 2);  //Warning: unreachable code ;) 

La solución más simple parece ser este elenco

Byte by1 = (Byte)(aboolean ? 1 : 2); 

Por lo tanto, sí, parece que el operador ternario está causando que las constantes "arreglen" sus tipos como ints y desactive la conversión de tipo implícita que de lo contrario obtendría de las constantes que se ajustan al tipo más pequeño.

+0

+1 por hacer un yeso menos feo que el mío :) – MPelletier

+1

Tu explicación tiene sentido. Pero, ¿por qué las constantes no se corregirían en esta circunstancia? Y doblemente curioso con el descubrimiento de Mendy. Alguien en Microsoft debería saberlo, y podría necesitar una fuerte discusión ... – MPelletier

+0

Creo que Mendy descubrió que cuando el compilador puede detectar trivialmente que puede optimizar por completo al operador ternario, el código de compilación es igual a 'Byte by = 2' que conserva la capacidad de emitir implícitamente. (vea mi comentario sobre la advertencia del compilador anterior) –

Cuestiones relacionadas