为什么 C# 不能将包含装箱 int 的对象转换为 double?

问题描述 投票:0回答:2

在 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 应该有效的证明。

c# casting integer double boxing
2个回答
1
投票

因为对我来说,工作示例 1 和 3 看起来像是示例 2 应该有效的证明。

不,它们是非常不同的转换。

C# 定义了从

int
double
的转换(请参阅 C# 7 标准草案的第 10.2.3 节)。但是拆箱转换的定义非常不同,在 section 10.3.7:

non_nullable_value_type 的拆箱操作包括首先检查对象实例是否是给定 non_nullable_value_type 的装箱值,然后将该值复制出实例。

...

如果源操作数是对不兼容对象的引用,则会抛出

System.InvalidCastException

在示例 2 中,对象实例不是类型为

double
的装箱值 - 它是
int
类型的装箱值,因此上述检查失败。

事实上,.NET CLR 在拆箱方面比 C# 要求的宽容一些;您可以从装箱的

int
拆箱到
uint
或反之亦然,也可以从枚举拆箱到其基础类型,反之亦然。但它不允许任何需要 representation 更改的内容,例如
int
double

如果您想要这些规则的理由,请这样想:为了执行任何执行实际工作的转换(而不是仅仅将位模式从一个地方复制到另一个地方),编译器需要告诉CLR 要执行哪些转换。对于拆箱操作,“实际”类型仅在执行时才知道,因此编译器无法指示 CLR 做什么。 CLR 可以有更复杂的规则,以便 it 可以根据执行时类型执行转换 - 但这会误入通常基于语言的领域。


1
投票
implicit conversion operator

的运算符,您可以在此

link
中找到更多信息,并且这恰好是在编译器级别实现的。它起作用的原因是编译器知道 Int32 整数可以在编译时完全用
Double
类型变量表示。
在您的示例2中,它不起作用的原因是在拆箱过程中,您必须先将其强制转换回原始类型,以便运行时可以确保类型安全。 

也参考其他答案

。 相反,您可以更改示例 2,如下所示,以便它运行时不会出现运行时抱怨,这在某种程度上解释了示例 1 如何在幕后工作,并明确地将强制类型转换为 double。 int myValue2 = 22; object myObject2 = myValue2; double resultFromBoxedInt = (double)(int)myObject2;

© www.soinside.com 2019 - 2024. All rights reserved.