64 votes

Pourquoi ne puis-je pas déballer un int en décimal?

J'ai un IDataRecord reader que je suis de la récupération d'une virgule comme suit:

decimal d = (decimal)reader[0];

Pour une raison quelconque, cela jette une défaillance de cast exception en disant que le "cast Spécifié n'est pas valide."

Quand je le fais, reader[0].GetType() il me dit qu'il est un Int32. Autant que je sache, ce ne devrait pas être un problème....

J'ai testé ce par ce fragment de code qui fonctionne très bien.

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

Cela m'a laissé de me gratter la tête en se demandant pourquoi il ne s'est pas unbox l'int contenues dans le lecteur comme un nombre décimal.

Personne ne sait pourquoi cela pourrait se produire? Est-il quelque chose de subtil qui me manque?

85voto

Mehrdad Afshari Points 204872

Vous ne pouvez unbox un type de valeur à son type d'origine (et la nullable version de ce type).

Par ailleurs, c'est valable (juste un raccourci pour votre deux version en ligne):

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

Pour la raison derrière cette lire ce Eric Lippert l'entrée de blog: Représentation et de l'Identité

Personnellement, je classer les choses par la fonte de la syntaxe en quatre types différents de fonctionnement (qu'ils ont tous des instructions IL):

  1. Boxe (box IL d'instruction), et unboxing (unbox IL d'instruction),
  2. Casting à travers la inhertiance hiérarchie (comme dynamic_cast<Type> en C++, utilise castclass instruction IL à vérifier)
  3. La conversion entre les types primitifs (comme static_cast<Type> en C++, il y a beaucoup de IL des instructions pour les différents types de conversions entre types primitifs)
  4. L'appel de l'utilisateur défini opérateurs de conversion (au niveau IL, ils sont juste des appels de méthode appropriée op_XXX méthode).

15voto

Guffa Points 308133

Il n'y a pas de problème à transtyper int à decimal , mais lorsque vous déballez un objet, vous devez utiliser le type exact qu'il contient.

Pour décompresser la valeur int en une valeur decimal , décompressez-la d'abord en tant qu'int, puis transformez-la en décimal:

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

L’interface IDataRecord dispose également de méthodes permettant de décompresser la valeur:

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

3voto

user276648 Points 850

Mehrdad Afshari dit:

Vous ne pouvez unbox un type de valeur à son type d'origine (et la nullable la version de ce type).

La chose à comprendre, c'est qu' il y a une différence entre la coulée et unboxing. jerryjvl avait une excellente remarque

Dans un sens, c'est une honte que l'unboxing et le casting du point de vue syntaxique look identiques, car elles sont très différentes opérations.

Casting:

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

Boxing/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?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X