奇怪的铸造行为。无法将object(int)强制转换为long

时间:2010-08-22 13:44:05

标签: c# .net clr

我有以下代码:

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?

为什么第二次投射不起作用?我意识到这可能是因为对象没有显式转换为long,但是如果我们在运行时查看它的类型,它就是System.Int32

如果我使用vardynamic代替object,则可以使用。

有什么想法吗?

5 个答案:

答案 0 :(得分:48)

int投射到long被解释为两种类型之间的转换。

object投射到int被解释为拆箱装箱int

它的语法相同,但它表示两种不同的东西。

在工作案例中(intlongobject(加框int)→int),编译器确切地知道要生成哪些代码。如果装箱intlong起作用,编译器必须以某种方式确定要使用的转换,但它没有足够的信息来执行此操作。

另见this blog post from Eric Lippert

答案 1 :(得分:7)

object包含int类型。但它被认为是一个对象(它是一个盒装的int),盒装值类型通常只能转换为它的底层类型(盒装的类型)。

要将其转换为其他类型,首先必须将其强制转换为其基础类型。这样可行:

long longNumber2 = (long) (int) intNumber2;

var的作用原因是编译器在编译时推断出类型。这意味着,当您使用var时,intNumber2(如果您使用typeof)的类型将为int。而当您使用object时,类型将为object

使用dynamic是一个完全不同的过程,无法与var进行比较。这里,转换/转换使用反射和DLR库在运行时进行。它将动态查找基础类型,发现它具有转换运算符并使用它。

答案 2 :(得分:3)

(警告:猜猜)

Int32有一个转换运算符Int64,这是第一次投射时调用的内容。 Object没有,所以你的第二个演员试图将一个对象转换为另一个不是超类型的类型(Int64不继承Int32)。

它与var一起使用的原因很明显 - 在这种情况下,编译器只会使您免于键入int。使用dynamic,运行时会对需要执行的操作进行所有必要的检查,而编译器通常只需插入强制转换或调用转换运算符。

答案 3 :(得分:1)

由于两种不同类型的演员阵容(一次转换,另一次拆箱)已经在答案中说明它不起作用。可能有用的补充是Convert.ToInt64()将任何可以转换为long的内置类型或实现IConvertible.ToInt64()的类的类型转换为long。换句话说,如果您希望能够将包含整数(任何大小)的对象转换为long,Convert.ToInt64()是可行的方法。它更贵,但你想要做的 比铸造更昂贵,而且差别是可以忽略的(只要你知道对象必须是一个盒装的长的话就足够浪费)

答案 4 :(得分:0)

您需要取消装箱与装箱的相同类型。

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

long result = (long)intNumber2;