Pourquoi ne puis-je unbox un int comme décimal?
Question
J'ai un IDataRecord reader
que je récupérer une décimale de la façon suivante:
decimal d = (decimal)reader[0];
Pour une raison quelconque cela jette une exception coulée invalide en disant que le « cast spécifié est incorrect. »
Quand je ne reader[0].GetType()
il me dit qu'il est un Int32. Pour autant que je sache, cela ne devrait pas être un problème ....
Je l'ai testé ce par cet extrait qui fonctionne très bien.
int i = 3750;
decimal d = (decimal)i;
Cela m'a laissé me gratter la tête se demandant pourquoi il ne parvient pas à unbox l'int contenu dans le lecteur comme une décimale.
Quelqu'un sait-il pourquoi cela pourrait se produire? Y at-il quelque chose de subtil qui me manque?
La solution
Vous ne pouvez unbox un type de valeur à son type d'origine (et la version annulable de ce type).
Par ailleurs, cela est valable (juste un raccourci pour vos 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 lecture de cette Eric l'entrée de blog de Lippert: représentation et identité
Personnellement, je catégoriser les choses par la syntaxe de fonte en quatre différents types d'opérations (ils ont toutes les instructions d'IL différentes):
- Boxing (
box
d'instruction IL) et unboxing (unbox
instruction IL) - coulée à travers la hiérarchie de inhertiance (comme
dynamic_cast<Type>
en C ++, utilise instructioncastclass
pour vérifier l'IL) - coulée entre les types primitifs (tels que
static_cast<Type>
en C ++, il y a beaucoup d'instructions de IL pour différents types de conversions entre des types primitifs) - L'appel des opérateurs de conversion définis par l'utilisateur (au niveau IL ils sont juste méthode appelle la méthode de
op_XXX
appropriée).
Autres conseils
Il n'y a pas de problème en jetant un int
à decimal
, mais quand vous unboxing un objet vous devez utiliser le type exact que l'objet contient.
Pour unbox la valeur int
en une valeur de decimal
, vous devez d'abord Unbox comme un int, puis convertion en décimal:
decimal d = (decimal)(int)reader[0];
L'interface IDataRecord a également des procédés pour le déballage de la valeur:
decimal d = (decimal)reader.GetInt32(0);
Voici une solution simple. Il prend soin de unboxing puis coulée en décimal. A travaillé très bien pour moi.
decimal d = Convert.ToDecimal(reader[0]); // reader[0] is int
Mehrdad Afshari l'a dit:
Vous ne pouvez unbox un type de valeur à son type d'origine (et annulable version de ce type).
La chose à réaliser est que il y a une différence entre la coulée et unboxing . jerryjvl avait une excellente remarque
Dans un sens, il est dommage que unboxing et casting regard syntaxiquement identiques, étant donné que ce sont des opérations très différentes.
Avec:
int i = 3750; // Declares a normal int
decimal d = (decimal)i; // Casts an int into a decimal > OK
Boxe / 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?