web-dev-qa-db-ja.com

奇妙なキャスト動作。オブジェクト(int)をlongにキャストできません

私は次のコードを持っています:

int intNumber1 = 100;
object intNumber2 = 100;
bool areNumberOfTheSameType = intNumber1.GetType() == intNumber2.GetType(); // TRUE
bool areEqual = intNumber1.Equals(intNumber2); // TRUE

long longNumber1 = (long) intNumber1; // OK
long longNumber2 = (long) intNumber2; // InvalidCastException. Why?

2番目のキャストが機能しないのはなぜですか?オブジェクトにlongへの明示的なキャストがないためか、実行時にそのタイプを見るとSystem.Int32

varの代わりにdynamicまたはobjectを使用すると、機能します。

何かご意見は?

45

intからlongへのキャストは、2つのタイプ間の変換として解釈されます。

objectからintへのキャストは、ボックス化されたintのボックス化解除として解釈されます。

構文は同じですが、2つの異なることを述べています。

作業ケース(intlongobject(boxed int)→int)では、コンパイラーはどのコードに作物。ボックス化されたintlongが機能する場合、コンパイラーはどの変換を使用するかを何らかの方法で判断する必要がありますが、それを行うための十分な情報がありません。

Eric Lippertからのこのブログ投稿 も参照してください。

53
svick

objectは型intを保持します。ただし、これはオブジェクト(ボックス化されたint)と見なされ、ボックス化された値の型は通常、その基になる型(ボックス化された型)にのみキャストできます。

それを別のタイプにキャストするには、まずそれをその基礎となるタイプにキャストする必要があります。これは機能します。

long longNumber2 = (long) (int) intNumber2;

varが機能するのは、コンパイラがコンパイル時に型を推測するためです。つまり、varを使用する場合、intNumber2のタイプ(typeofを使用する場合)はintになります。 objectを使用する場合、タイプはobjectになります。

dynamicの使用はまったく異なるプロセスであり、varと比較することはできません。ここでは、リフレクションとDLRライブラリを使用して、変換/キャストが実行時に行われます。基になる型を動的に見つけ、変換演算子があり、それを使用します。

7
Abel

(注意:推測)

Int32には、最初のキャストを実行したときに呼び出されるInt64への変換演算子があります。 Objectはサポートしていません。そのため、2番目のキャストは、オブジェクトをスーパータイプではない別のタイプにキャストしようとしています(Int64Int32を継承しません)。

varで機能する理由は明白です。その場合、コンパイラーはintを入力する手間を省きます。 dynamicを使用すると、ランタイムは実行する必要があるすべての必要なチェックを行いますが、通常、コンパイラーはキャストを挿入するか、変換演算子を呼び出します。

3
Joey

2つの異なるタイプのキャスト(1つは変換、もう1つはボックス化解除)が原因で機能しないことは、ここの回答ですでに述べられています。便利な追加となる可能性があるのは、Convert.ToInt64()が、longに変換できる組み込み型、またはIConvertible.ToInt64()を実装するクラスの型のいずれかであるものを変換することです。ロングに。言い換えると、整数を含むオブジェクト(任意のサイズ)をlongにキャストできるようにしたい場合は、Convert.ToInt64()が適しています。それはより高価ですが、あなたがやろうとしていることisキャストよりも高価であり、その違いは無視できます(オブジェクトがボックス化された長いものでなければならないことがわかっている場合、無駄になるほど大きい) 。

1
Jon Hanna

ボックス化されたのと同じタイプにボックス化解除する必要があります。

object intNumber2 = 100L;
// or value in the long type range
// object intNumber2 = 9223372036854775806;

long result = (long)intNumber2;
0
Peter Kelly