int を 10 進数としてボックス化できないのはなぜですか?
質問
を持っています IDataRecord reader
次のように小数を取得しています。
decimal d = (decimal)reader[0];
何らかの理由で、これにより、「指定されたキャストは無効です」という無効なキャスト例外がスローされます。
私がする時 reader[0].GetType()
それは Int32 であることがわかります。私の知る限り、これは問題ないはずです...
このスニペットでこれをテストしましたが、問題なく機能します。
int i = 3750;
decimal d = (decimal)i;
このため、リーダーに 10 進数として含まれる int をアンボックス化できないのはなぜかと頭を悩ませました。
なぜこれが起こるのか知っている人はいますか?何か微妙なところが欠けているのでしょうか?
解決
値型をボックス化解除して元の型 (およびその型の null 許容バージョン) にすることのみが可能です。
ちなみに、これは有効です (2 行バージョンの短縮形にすぎません)。
object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion
この背後にある理由については、これをお読みください エリック・リッパートのブログエントリー:表現とアイデンティティ
個人的に、私はキャスト構文によって実行される処理を 4 つの異なるタイプの操作に分類します (これらはすべて異なる IL 命令を持ちます)。
- ボクシング (
box
IL 命令) と開梱 (unbox
IL命令) - 継承階層を介したキャスト (例:
dynamic_cast<Type>
C++ では、使用しますcastclass
確認するための IL 命令) - プリミティブ型間のキャスト (例:
static_cast<Type>
C++ では、プリミティブ型間のさまざまな型のキャスト用の IL 命令が多数あります) - ユーザー定義の変換演算子の呼び出し (IL レベルでは、それらは適切な関数への単なるメソッド呼び出しです)
op_XXX
方法)。
他のヒント
がありint
するdecimal
をキャストには問題はありませんが、あなたがオブジェクトをアンボクシングされているときは、オブジェクトが含まれている正確な型を使用する必要があります。
int
値にdecimal
値をUnboxのために、あなたはまず、intとしてそれをUnboxの小数点にキャストします:
decimal d = (decimal)(int)reader[0];
IDataRecordインターフェースは、値をボックス化解除するためのメソッドがあります。
decimal d = (decimal)reader.GetInt32(0);
ここで簡単なソリューションです。それはアンボクシングの世話をして、小数点にキャスト。私のためにうまく働きました。
decimal d = Convert.ToDecimal(reader[0]); // reader[0] is int
Mehrdad Afshariはそれを言っます:
あなたはその元の型への値の型(およびNULL可能にVHS版のみすることができます そのタイプのバージョン)。
を実現する事はを鋳造し、アンボクシングの間に差があるということです。 jerryjvlは、優れた発言があった。
ある意味でそれはアンボクシングとキャスト構文的に見えることを残念です 同じ、彼らは非常に異なる操作なのでます。
鋳造ます:
int i = 3750; // Declares a normal int
decimal d = (decimal)i; // Casts an int into a decimal > OK
ボクシング/アンボクシングます:
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?