Warum kann ich nicht ein int als Dezimalzahl unbox?
Frage
Ich habe eine IDataRecord reader
, dass ich eine Dezimalzahl aus bin Abrufen wie folgt:
decimal d = (decimal)reader[0];
Aus irgendeinem Grund dies eine ungültige Cast Exception wirft sagen, dass die „angegebene Umwandlung ungültig ist.“
Wenn ich reader[0].GetType()
es mir sagt, dass es ein Int32 ist. Soweit ich weiß, ist dies kein Problem ....
Ich habe das diesen Schnipsel erprobt, die ganz gut funktioniert.
int i = 3750;
decimal d = (decimal)i;
Das hat mich verlassen Kratzen meinem Kopf fragen, warum es versagt unbox die int im Leser als Dezimalzahl enthalten.
Weiß jemand, warum dies geschieht werden könnte? Gibt es etwas subtiler ich fehle?
Lösung
Sie können nur einen Werttyp in seinen ursprünglichen Typ (und die Nullable-Version dieses Typs) unbox.
übrigens, dies gilt (nur eine Abkürzung für Ihre zwei Zeilenversion):
object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion
Aus dem Grund dahinter lesen Sie Eric Lippert Blogeintrag: Repräsentation und Identität
Ich persönlich kategorisieren Dinge durch Guss Syntax in vier verschiedene Arten von Operationen durchgeführt (sie alle unterschiedlich IL Anweisungen haben):
- Boxen (
box
IL-Anweisung) und Unboxing (unbox
IL-Anweisung) - die inhertiance Hierarchie durch Gießen (wie
dynamic_cast<Type>
in C ++,castclass
IL-Befehl verwendet, um zu überprüfen) - Casting zwischen primitiven Typen (wie
static_cast<Type>
in C ++, es gibt viele IL Anweisungen für die verschiedenen Arten von Abgüssen zwischen primitiven Typen) - Benutzer aufrufen definiert Konvertierungsoperatoren (bei der IL-Ebene sind sie nur Methodenaufrufe an die entsprechende
op_XXX
Methode).
Andere Tipps
Es gibt kein Problem in Gießen einen int
decimal
, aber wenn Sie ein Objekt Unboxing Sie haben die genaue Art zu verwenden, die das Objekt enthält.
den int
Wert in einen decimal
Wert Um unbox, Sie es zuerst als int unbox, es dann auf Dezimal Stimmen:
decimal d = (decimal)(int)reader[0];
Die IDataRecord Schnittstelle hat auch Methoden für Unboxing den Wert:
decimal d = (decimal)reader.GetInt32(0);
Hier ist eine einfache Lösung. Es kümmert sich um Unboxing und dann in Dezimalzahlen Gießen. Funktionierte gut für mich.
decimal d = Convert.ToDecimal(reader[0]); // reader[0] is int
Mehrdad Afshari sagte er:
Sie können nur unbox einen Werttyp in seinen ursprünglichen Typ (und die NULL-Werte zulassen Version dieses Typs).
Das ist daran zu erkennen ist, dass gibt es einen Unterschied zwischen dem Gießen und Unboxing . jerryjvl hatte eine ausgezeichnete Bemerkung
In gewisser Weise ist es eine Schande, dass Unboxing und Casting syntaktisch aussehen identisch, da sie sehr unterschiedliche Vorgänge.
Casting:
int i = 3750; // Declares a normal int
decimal d = (decimal)i; // Casts an int into a decimal > OK
Boxen / 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?