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

时间:2022-09-01 10:14:18

I have the following code:

我有以下代码:

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?

Why doesn't the second cast work? I realize that it might be because the object doesn’t have an explicit cast to a long, but if we look at its type on runtime it is System.Int32.

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

If I use var or dynamic instead of object, it works.

如果我使用var或dynamic而不是object,它可以工作。

Any thoughts?

有什么想法吗?

5 个解决方案

#1


45  

Cast from int to long is interpreted as conversion between the two types.

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

Cast from object to int is interpreted as unboxing a boxed int.

从对象转换为int被解释为拆箱装箱的int。

It is the same syntax, but it says two different things.

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

In the working cases (intlong, object (boxed int)→int), the compiler knows exactly what code to produce. If boxed intlong was to work, the compiler would have to somehow figure out which conversion to use, but it doesn't have enough information to do it.

在工作案例中(int→long,object(boxed int)→int),编译器确切地知道要生成什么代码。如果boxed int→long工作,编译器必须以某种方式确定要使用哪个转换,但它没有足够的信息来执行它。

See also this blog post from Eric Lippert.

另请参阅Eric Lippert撰写的这篇博客文章。

#2


5  

The object holds a type int. But it's considered an object (which is a boxed int) and a boxed value type can generally only be cast to its underlying type (the type that is boxed).

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

To cast it to another type, you first have to cast it to its underlying type. This works:

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

long longNumber2 = (long) (int) intNumber2;

The reason that var works is that the compiler infers the type at compile time. That means, when you use var, the type of intNumber2 (if you use typeof) will be int. Whereas when you use object, the type will be object.

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

Using dynamic is a whole different process and cannot be compared with var. Here, the conversion / casting takes place at runtime, using reflection and the DLR library. It will dynamically find the underlying type, find that it has a conversion operator and uses that.

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

#3


3  

(Caution: Guess)

(警告:猜猜)

Int32 has a conversion operator to Int64 which is what gets invoked when you do the first cast. Object doesn't, so your second cast is trying to cast an object to another type which isn't a supertype (Int64 doesn't inherit Int32).

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

The reason why it works with var is obvious – the compiler just saves you from typing int in that case. With dynamic the runtime does all necessary checks for what needs to be done while normally the compiler would just insert either the cast or invoke the conversion operator.

它与var一起使用的原因显而易见 - 编译器只是在这种情况下保存您不会输入int。使用动态,运行时会对需要执行的操作执行所有必要的检查,而编译器通常只插入强制转换或调用转换运算符。

#4


1  

That it doesn't work due to being two different types of casts (one converting, the other unboxing) has already been stated in answers here. What might be a useful addition, is that Convert.ToInt64() will convert anything that is either a built-in type that can be converted to long, or a type of a class that implements IConvertible.ToInt64(), into a long. In other words, if you want to be able to cast an object that contains an integer (of whatever size) to long, Convert.ToInt64() is the way to go. It is more expensive, but what you are trying to do is more expensive that casting, and the difference is negliable (just big enough to be wasteful in cases where you know the object must be a boxed long).

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

#5


0  

You need to unbox to the same type that was boxed.

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

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

long result = (long)intNumber2;

#1


45  

Cast from int to long is interpreted as conversion between the two types.

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

Cast from object to int is interpreted as unboxing a boxed int.

从对象转换为int被解释为拆箱装箱的int。

It is the same syntax, but it says two different things.

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

In the working cases (intlong, object (boxed int)→int), the compiler knows exactly what code to produce. If boxed intlong was to work, the compiler would have to somehow figure out which conversion to use, but it doesn't have enough information to do it.

在工作案例中(int→long,object(boxed int)→int),编译器确切地知道要生成什么代码。如果boxed int→long工作,编译器必须以某种方式确定要使用哪个转换,但它没有足够的信息来执行它。

See also this blog post from Eric Lippert.

另请参阅Eric Lippert撰写的这篇博客文章。

#2


5  

The object holds a type int. But it's considered an object (which is a boxed int) and a boxed value type can generally only be cast to its underlying type (the type that is boxed).

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

To cast it to another type, you first have to cast it to its underlying type. This works:

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

long longNumber2 = (long) (int) intNumber2;

The reason that var works is that the compiler infers the type at compile time. That means, when you use var, the type of intNumber2 (if you use typeof) will be int. Whereas when you use object, the type will be object.

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

Using dynamic is a whole different process and cannot be compared with var. Here, the conversion / casting takes place at runtime, using reflection and the DLR library. It will dynamically find the underlying type, find that it has a conversion operator and uses that.

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

#3


3  

(Caution: Guess)

(警告:猜猜)

Int32 has a conversion operator to Int64 which is what gets invoked when you do the first cast. Object doesn't, so your second cast is trying to cast an object to another type which isn't a supertype (Int64 doesn't inherit Int32).

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

The reason why it works with var is obvious – the compiler just saves you from typing int in that case. With dynamic the runtime does all necessary checks for what needs to be done while normally the compiler would just insert either the cast or invoke the conversion operator.

它与var一起使用的原因显而易见 - 编译器只是在这种情况下保存您不会输入int。使用动态,运行时会对需要执行的操作执行所有必要的检查,而编译器通常只插入强制转换或调用转换运算符。

#4


1  

That it doesn't work due to being two different types of casts (one converting, the other unboxing) has already been stated in answers here. What might be a useful addition, is that Convert.ToInt64() will convert anything that is either a built-in type that can be converted to long, or a type of a class that implements IConvertible.ToInt64(), into a long. In other words, if you want to be able to cast an object that contains an integer (of whatever size) to long, Convert.ToInt64() is the way to go. It is more expensive, but what you are trying to do is more expensive that casting, and the difference is negliable (just big enough to be wasteful in cases where you know the object must be a boxed long).

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

#5


0  

You need to unbox to the same type that was boxed.

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

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

long result = (long)intNumber2;