63

IDataRecord reader次のように小数を取得していることがあります。

decimal d = (decimal)reader[0];

何らかの理由で、これは「指定されたキャストが無効です」という無効なキャスト例外をスローします。

私がそうするときreader[0].GetType()、それはそれがInt32であることを私に告げます。私の知る限り、これは問題ではないはずです。

私はこれをこのスニペットでテストしましたが、これは問題なく機能します。

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

これにより、リーダーに含まれるintを小数としてアンボックス化できないのはなぜかと頭を悩ませました。

なぜこれが起こっているのか誰かが知っていますか?私が見逃している微妙なものはありますか?

4

4 に答える 4

83

値型を元の型(およびその型のnull許容バージョン)にのみボックス化解除できます。

ちなみに、これは有効です(2行バージョンの省略形):

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

この背後にある理由については、このエリックリッパートのブログエントリを読んでください:表現とアイデンティティ

個人的に、私はキャスト構文によって行われることを4つの異なるタイプの操作に分類します(それらはすべて異なるIL命令を持っています):

  1. ボクシング(boxIL命令)とアンボクシング(unboxIL命令)
  2. 継承階層を介したキャスト(dynamic_cast<Type>C ++の場合と同様に、castclassIL命令を使用して検証します)
  3. プリミティブ型間のキャスト(C ++のようstatic_cast<Type>に、プリミティブ型間のさまざまなタイプのキャスト用のIL命令がたくさんあります)
  4. ユーザー定義の変換演算子の呼び出し(ILレベルでは、適切なop_XXXメソッドへのメソッド呼び出しにすぎません)。
于 2009-07-06T01:52:48.777 に答える
15

inttoをキャストすることに問題はありませんdecimalが、オブジェクトのボックスを解除するときは、オブジェクトに含まれる正確なタイプを使用する必要があります。

値のボックスを解除してint値にするにはdecimal、最初にintとしてボックスを解除してから、10進数にキャストします。

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

IDataRecordインターフェースには、値を箱から出すためのメソッドもあります。

decimal d = (decimal)reader.GetInt32(0);
于 2009-07-06T01:55:25.840 に答える
15

これが簡単な解決策です。ボックス化解除と 10 進数へのキャストを処理します。私にとってはうまくいきました。

decimal d = Convert.ToDecimal(reader[0]);  // reader[0] is int
于 2015-12-28T20:59:42.470 に答える
3

Mehrdad Afshari は次のように述べています。

値型を元の型 (およびその型の null 許容バージョン) にのみボックス化解除できます。

認識すべきことは、キャストとボックス化解除には違いがあるということです。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?
于 2011-10-04T04:35:56.637 に答える