Pregunta

Yo tengo un IDataRecord reader del que estoy recuperando un decimal de la siguiente manera:

decimal d = (decimal)reader[0];

Por alguna razón, esto genera una excepción de conversión no válida que dice que "la conversión especificada no es válida".

Cuando lo hago reader[0].GetType() me dice que es un Int32.Hasta donde yo sé esto no debería ser un problema....

Lo probé con este fragmento que funciona bien.

int i = 3750;
decimal d = (decimal)i;

Esto me ha dejado rascándome la cabeza preguntándome por qué no se puede desempaquetar el int contenido en el lector como decimal.

¿Alguien sabe por qué podría estar ocurriendo esto?¿Hay algo sutil que me estoy perdiendo?

¿Fue útil?

Solución

Solo puede desempaquetar un tipo de valor a su tipo original (y la versión anulable de ese tipo).

Por cierto, esto es válido (sólo una abreviatura de su versión de dos líneas):

object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion

Por la razón detrás de esto lee esto Entrada del blog de Eric Lippert:Representación e identidad

Personalmente, clasifico las cosas realizadas mediante sintaxis de conversión en cuatro tipos diferentes de operaciones (todas tienen diferentes instrucciones IL):

  1. boxeo (box instrucción IL) y unboxing (unbox instrucción IL)
  2. Transmitir a través de la jerarquía de herencia (como dynamic_cast<Type> en C++, utiliza castclass Instrucción IL para verificar)
  3. Lanzamiento entre tipos primitivos (como static_cast<Type> en C++, hay muchas instrucciones IL para diferentes tipos de conversiones entre tipos primitivos)
  4. Llamar a operadores de conversión definidos por el usuario (en el nivel IL, son solo llamadas a métodos al operador apropiado). op_XXX método).

Otros consejos

No hay ningún problema en que emitan un int a decimal, pero cuando se está unboxing un objeto que tiene que utilizar el tipo exacto que el objeto contiene.

Para desempacar el valor int en un valor decimal, primero unbox como un int, y luego convertirlo a decimal:

decimal d = (decimal)(int)reader[0];

La interfaz IDataRecord también tiene métodos para unboxing el valor:

decimal d = (decimal)reader.GetInt32(0);

Esta es una solución simple. Se ocupa de unboxing y luego fundición a decimal. Trabajado bien para mí.

decimal d = Convert.ToDecimal(reader[0]);  // reader[0] is int

Mehrdad Afshari dijo que:

  

Sólo puede desempacar un tipo de valor a su tipo original (y el anulable   versión de ese tipo).

Lo que hay que darse cuenta es que hay una diferencia entre la fundición y unboxing . jerryjvl tuvo una excelente observación

  

En un sentido es una pena que unboxing y echando un vistazo sintácticamente   idénticos, ya que son muy diferentes operaciones.

Con:

int i = 3750; // Declares a normal int
decimal d = (decimal)i; // Casts an int into a decimal > OK

Boxeo / Unboxing:

object i = 3750; // Boxes an int ("3750" is similar to "(int)3750")
decimal d = (decimal)i; // Unboxes the boxed int into a decimal > KO, can only unbox it into a int or int?
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top