¿Por qué la excepción (int) (objeto) de 10m arroja el “lanzamiento especificado no es válido”?

Por qué este lanzamiento explícito arroja un lanzamiento Specified cast is not valid. excepción?

 decimal d = 10m; object o = d; int x = (int)o; 

Pero esto funciona:

 int x = (int)(decimal)o; 

Un valor en caja solo se puede desempaquetar en una variable del mismo tipo. Esta restricción aparentemente extraña es una optimización de velocidad muy importante que hizo .NET 1.x factible antes de que los generics estuvieran disponibles. Puedes leer más sobre esto en esta respuesta .

No tiene que saltar a través del bastidor moldeado múltiple, los tipos de valores simples implementan la interfaz IConvertible. Que invocas usando la clase Convert:

  object o = 12m; int ix = Convert.ToInt32(o); 

Cuando haces esto, estás implícitamente encajonando el decimal d en un objeto básico:

 object o = d; 

No puede enviar valores encuadrados directamente sin antes desempaquetarlos, por lo que no se puede realizar el envío directo a un int, como en el siguiente ejemplo:

 int x = (int)o; 

Sin embargo, al hacer esto (fundición intermedia a decimal primero):

 int x = (int)(decimal)o; 

Primero está desempaquetando o , lo que significa que está recuperando el valor decimal, y luego transfiere el valor decimal sin caja a un int, que funciona porque C # admite fundir decimales en ints.

decimal tiene un operador de int explícita a int . object no:

 decimal d = 10m; object o = d; int x = (int)d; // OK, calls decimal.explicit operator int(d). int y = (int)o; // Invalid cast. 

Lo que debes pensar aquí es que boxear y desempaquetar no es exactamente un tipo de conversión. Simplemente “ajusta” el tipo de objeto “alrededor” del tipo decimal inicial. Es por eso que primero debe desagrupar el objeto, antes de poder convertirlo a un número entero.