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

Gil*_*son 0 c# double boxing integer casting

在 C# 中,示例 1 为何有效:

int myValue1 = 11;
double resultDirectlyFromInt = myValue1;
Run Code Online (Sandbox Code Playgroud)

但示例 2 没有:

int myValue2 = 22;
object myObject2 = myValue2;
double resultFromBoxedInt = (double)myObject2;
Run Code Online (Sandbox Code Playgroud)

示例 3 再次起作用:

double myValue3 = 33.3;
object myObject3 = myValue3;
double resultFromBoxedDouble = (double)myObject3;
Run Code Online (Sandbox Code Playgroud)

有人可以解释其背后的理由吗?因为对我来说,工作示例 1 和 3 看起来像是示例 2 应该有效的证明。

Jon*_*eet 5

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

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

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

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

...

如果源操作数是对不兼容对象的引用,System.InvalidCastException则抛出 a 。

在示例 2 中,对象实例不是type的装箱值double- 它是 type 的装箱值int,因此上述检查失败。

碰巧的是,.NET CLR 在拆箱方面比 C# 要求的宽容一些。您可以从装箱int到 a取消uint装箱,反之亦然,也可以从枚举取消装箱到其基础类型,反之亦然。但它不允许任何需要改变表示的事情,int比如double.

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