2010-08-22 14 views
37

tengo el siguiente código:Comportamiento de fundición extraño. No se puede convertir objeto (int) a largo

int intNumber1 = 100; 
object intNumber2 = 100; 
bool areNumberOfTheSameType = intNumber1.GetType() == intNumber2.GetType(); // TRUE 
bool areEqual = intNumber1.Equals(intNumber2); // TRUE 

long longNumber1 = (long) intNumber1; // OK 
long longNumber2 = (long) intNumber2; // InvalidCastException. Why? 

¿Por qué no el segundo trabajo de reparto? Me doy cuenta de que puede deberse a que el objeto no tiene un molde explícito a largo, pero si miramos su tipo en tiempo de ejecución es System.Int32.

Si uso var o dynamic en lugar de object, funciona.

¿Alguna idea?

+4

intente cambiar eso a 'long longNumber2 = (long) (int) intNumber2;' –

+0

¿Por qué le gustaría usar un objeto en lugar de var en esta instancia? Es mejor mantener las variables fuertemente tipadas donde sea posible –

+1

@ Quinn351: supongo que el código anterior ilustra un problema simplificado que el usuario tiene, no creo que debamos tomarlo como una práctica actual. – Abel

Respuesta

42

Emitir desde int hasta long se interpreta como la conversión entre los dos tipos.

Emitir de object a int se interpreta como unboxing un int en caja.

Es la misma sintaxis, pero dice dos cosas diferentes.

En los casos de trabajo (intlong, object (en caja int) → int), el compilador sabe exactamente qué código para producir. Si el recuadro intlong fuera a funcionar, el compilador tendría que averiguar de alguna manera qué conversión usar, pero no tiene suficiente información para hacerlo.

Véase también this blog post from Eric Lippert.

+2

@Bashir Magomedov: la publicación del blog de Eric Lippert sobre esto es bastante buena, le recomiendo encarecidamente que la lea. – R0MANARMY

+0

@ R0MANARMY ¡Gracias chicos! Lo he leído. Es muy completo @svick. Gracias. Está claro ahora. –

3

(Precaución: Guess)

Int32 tiene un operador de conversión a Int64 que es lo que se invoca cuando se hace el primer lanzamiento. Object no, por lo que su segundo elenco está tratando de convertir un objeto a otro tipo que no sea un supertipo (Int64 no hereda Int32).

La razón por la que funciona con var es obvia: el compilador simplemente le evita escribir int en ese caso. Con dynamic el tiempo de ejecución realiza todas las comprobaciones necesarias de lo que se debe hacer, mientras que normalmente el compilador simplemente inserta el molde o invoca al operador de conversión.

5

El object tiene un tipo int. Pero se considera un objeto (que es un int encuadrado) y un tipo de valor encuadrado generalmente solo se puede convertir a su tipo subyacente (el tipo que está encuadrado).

Para convertirlo en otro tipo, primero debe convertirlo en su tipo subyacente. Esto funciona:

long longNumber2 = (long) (int) intNumber2; 

La razón de que var funciona es que el compilador infiere el tipo en tiempo de compilación. Eso significa que, cuando usa var, el tipo de intNumber2 (si usa typeof) será int. Mientras que cuando usa object, el tipo será object.

El uso de dynamic es un proceso completamente diferente y no se puede comparar con var.Aquí, la conversión/conversión se lleva a cabo en tiempo de ejecución, utilizando la reflexión y la biblioteca DLR. Encontrará dinámicamente el tipo subyacente, encontrará que tiene un operador de conversión y lo usará.

0

Necesita unbox para el mismo tipo que estaba en caja.

object intNumber2 = 100L; 
// or value in the long type range 
// object intNumber2 = 9223372036854775806; 

long result = (long)intNumber2; 
+1

También puede agregar la 'L' al número, sin necesidad de un número grande. – Abel

+0

¡De hecho! Agregaré eso a la respuesta para mostrar ambas formas. –

1

Eso no funciona debido a ser de dos tipos diferentes de moldes (una conversión, el otro unboxing) ya se ha indicado en respuestas aquí. Lo que podría ser una adición útil, es que Convert.ToInt64() convertirá todo lo que sea un tipo incorporado que se puede convertir a largo, o un tipo de una clase que implementa IConvertible.ToInt64(), en un largo. En otras palabras, si desea poder convertir un objeto que contiene un entero (de cualquier tamaño) a largo, Convert.ToInt64() es el camino a seguir. Es más caro, pero lo que está tratando de hacer es más caro que la fundición, y la diferencia es negligente (lo suficientemente grande como para ser un desperdicio en los casos en que sabe que el objeto debe tener un largo en caja).

Cuestiones relacionadas