提问人:Gilles jr Bisson 提问时间:7/27/2023 最后编辑:Alexei LevenkovGilles jr Bisson 更新时间:7/30/2023 访问量:177
为什么 C# 不能将包含盒装 int 的对象强制转换为双精度值?
Why can't C# cast an object containing a boxed int to a double?
问:
在 C# 中,为什么示例 1 有效:
int myValue1 = 11;
double resultDirectlyFromInt = myValue1;
但示例 2 没有:
int myValue2 = 22;
object myObject2 = myValue2;
double resultFromBoxedInt = (double)myObject2;
示例 3 再次起作用:
double myValue3 = 33.3;
object myObject3 = myValue3;
double resultFromBoxedDouble = (double)myObject3;
有人可以解释这背后的理由吗?因为对我来说,工作示例 1 和 3 看起来像是示例 2 应该有效的证明。
答:
因为对我来说,工作示例 1 和 3 看起来像是示例 2 应该有效的证明。
不,它们是非常不同的转换。
C# 定义了从 to 的转换(请参阅 C# 7 标准草案的第 10.2.3 节)。但是,在第 10.3.7 节中,对拆箱转化的定义大不相同:int
double
对non_nullable_value_type的拆箱操作包括首先检查对象实例是否为给定non_nullable_value_type的装箱值,然后将该值从实例中复制出来。
...
如果源操作数是对不兼容对象的引用,则抛出 a。
System.InvalidCastException
在示例 2 中,对象实例不是 类型的装箱值 - 它是 类型的装箱值,因此上述检查失败。double
int
碰巧的是,.NET CLR 在拆箱方面比 C# 要求的更宽容一些;您可以从 Boxed 解箱到 A,反之亦然,也可以从 Enum 解箱到其基础类型,反之亦然。但它不允许任何需要表示更改的东西,比如 .int
uint
int
double
如果要为这些规则提供理由,可以这样想:为了执行执行实际工作的任何转换(而不是仅仅将位模式从一个位置复制到另一个位置),编译器需要告诉 CLR 要执行哪个转换。对于取消装箱操作,实际类型仅在执行时已知,因此编译器无法指示 CLR 执行的操作。CLR 可以有更复杂的规则,以便它可以根据执行时间类型执行转换 - 但这偏离了通常基于语言的领域。
评论
您的第一个示例实际上是调用名为 的运算符,您可以在此链接中找到更多信息,而这恰好是在编译器级别实现的。它之所以有效,是因为编译器知道整数可以在编译时完全表示在 -type 变量中。implicit conversion operator
Int32
Double
在示例 2 中,它不起作用的原因是在开箱时,必须先将其强制转换为原始类型,以便运行时可以保证类型安全。也可以参考其他答案。 相反,您可以按如下方式更改示例 2,以便它将在没有运行时抱怨的情况下运行,这在某种程度上解释了示例 1 如何在后台工作,强制转换加倍,但明确。
int myValue2 = 22;
object myObject2 = myValue2;
double resultFromBoxedInt = (double)(int)myObject2;
评论