2009-07-06 5 views
59

Ich habe eine IDataRecord reader, dass ich eine Dezimalzahl bin Abrufen aus wie folgt: „angegebene Ziel ungültig ist“Warum kann ich einen int nicht als Dezimalzahl ausgeben?

decimal d = (decimal)reader[0]; 

Aus irgendeinem Grund dieses Wort eine ungültige Besetzung Ausnahme auslöst, dass die

Wenn ich reader[0].GetType() mache, sagt es mir, dass es ein Int32 ist. Soweit ich weiß, sollte dies kein Problem sein ....

Ich habe dies durch dieses Schnipsel getestet, das funktioniert gut.

Das hat mich am Kopf kratzen lassen und mich gewundert, warum es nicht möglich ist, das Int im Lesegerät als Dezimalzahl auszupacken.

Weiß jemand, warum dies auftreten könnte? Gibt es etwas Feines, das ich vermisse?

Antwort

74

Sie können einen Werttyp nur auf seinen ursprünglichen Typ (und die nullfähige Version dieses Typs) zurücksetzen.

By the way, ist diese gültig ist (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 diese Eric Lippert's blog entry: Representation and Identity

persönlich lesen, ich Dinge durch Guss Syntax getan kategorisieren in vier verschiedenen Betriebsarten (sie alle unterschiedlich IL Anweisungen haben):

  1. Boxing (box IL-Anweisung) und Unboxing (unbox IL-Befehl)
  2. Casting durch die inhertiance Hierarchie (wie dynamic_cast<Type> in C++, verwendet castclass IL Anweisung zu verifizieren)
  3. Casting zwischen primitiven Typen (wie static_cast<Type> in C++ gibt es eine Fülle von IL Anweisungen für unterschiedliche Arten von Abgüssen zwischen primitive Typen)
  4. Aufrufen benutzerdefinierter Konvertierungsoperatoren (auf der IL-Ebene sind sie nur Methodenaufrufe an die entsprechende Methode op_XXX).
+20

In gewisser Weise ist es schade, dass Unboxing und Casting syntaktisch identisch aussehen, da sie sehr unterschiedliche Operationen sind. – jerryjvl

+0

Danke Mehrdad. Ihre Erklärung und der Link zu Erics Blog war sehr hilfreich. – mezoid

+0

Danke! Das warf mich auf eine Schleife. – Darryl

14

Es gibt kein Problem, eine int zu decimal in Gießen, aber wenn Sie ein Objekt Unboxing Sie haben den genauen Typ zu verwenden, der das Objekt enthält.

Um den int Wert in einen decimal Wert 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); 
+0

Danke für Ihre Antwort auch Guffa ... es war sehr hilfreich. – mezoid

+0

Aber wenn der Wert manchmal eine ganze Zahl ist, aber manchmal eine echte Dezimalzahl. Wird zuerst nach int umgewandelt, wird der Dezimalwert verloren. Wenn Sie ein Double erwarten, dann stellen Sie sicher, dass die Quelle Ihnen ein Dobule gibt. Andernfalls werden Sie Nebenwirkungen bekommen, die den Endbenutzer dazu bringen, sich die Haare zu kratzen und dann Ihre Augäpfel zu stoßen. Gute Antwort, aber sehr schlecht beraten- Es verdient eine -1 – ppumkin

+1

@ppumkin: Entschuldigung, wenn Sie die Antwort missverstanden haben. Es wird nicht nach "int" und dann nach "decimal" umgewandelt, es wird * unboxing * an 'int' und dann an 'dezimal' übergeben. Wenn Sie den Wert als "int" entpacken, wird er nie etwas verlieren, da es nicht möglich ist, ihn als "int" zu dekomprimieren, wenn es nicht wirklich ein "int" ist. – Guffa

3

Mehrdad Afshari sagte er:

Sie können nur einen Wert ty unbox pe zu seinem ursprünglichen Typ (und die Nullable Version dieses Typs).

Das ist daran zu erkennen ist, dass es einen Unterschied zwischen dem Gießen und Unboxing. jerryjvl hatte eine ausgezeichnete Bemerkung

In gewisser Weise ist es eine Schande, dass Unboxing und syntaktisch aussehen identisch Gießen, da sie sehr unterschiedliche Operationen sind.

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? 
12

Hier ist eine einfache Lösung. Es sorgt für das Unboxing und dann für das Dezimalen. Hat gut für mich funktioniert.

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