为什么我不能将装箱的整数转换为可空十进制数?

4
为什么会抛出InvalidCastException异常?有人能描述一下这种行为吗?
object zero = 0;
decimal? dec = (decimal?)zero;

@John Saunders:这是不合法的。 - jason
2个回答

15

一个装箱的 int 只能拆箱为 int。但是,下面这个是合法的:

object zero = 0;
decimal? dec = (decimal?)(int)zero;

请参阅MSDN或ECMA 334 C#规范以获取详细信息。关键在于以下内容:

拆箱是从对象类型到值类型的显式转换,或从实现该接口的值类型到接口类型的显式转换。拆箱操作包括:

  1. 检查对象实例以确保它是给定值类型的装箱值。
  2. 将值从实例复制到值类型变量中。

编辑:这篇文章值得从评论中提出。感谢Rob Kennedy!


好的,但为什么需要这种中间转换呢? - Przemaas
第一个强制转换(int)将装箱的int解包为int类型的值类型(这是合法操作)。第二个强制转换(decimal?)将结果int转换为decimal?。 - jason
1
@Michael Meadows:这是合法的:object zero = 0m; decimal? dec = (decimal)zero; 注意 'm' 明确告诉编译器,字面值 "0" 应被解释为十进制数。 - jason
@Jason,十进制数是一个对象,所以第一个例子是多态性。第二个例子是显式转换。我想说的是回答@Przemaas的评论。你必须先将“zero”变量显式转换为int,因为你不能将对象隐式转换为int,并且由于它不是INullable<decimal>,直接显式转换到该类型会失败。 - Michael Meadows
3
Eric Lippert针对这种工作方式进行了相当详细的解释。总结一下:将装箱对象拆箱成除了原始类型之外的任何其他类型,需要为所有不同的可能性生成大量代码,因为编译器不知道原始的装箱类型是什么。http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx - Rob Kennedy
显示剩余3条评论

0

看这篇文章 http://msdn.microsoft.com/en-us/magazine/cc301569.aspx

具体来说 "公共语言运行时首先确保引用类型变量不为空,并且它引用的是所需值类型的装箱值对象。如果任一测试失败,则会生成一个InvalidCastException异常。"

我认为你在那个值的对象上出了问题。我认为将其转换为int是有效的,因为0字面量将转换为int,然后int转换为decimal。

如果你这样做,它就能工作。

    decimal? test=0;
    object zero = test;
    decimal? dec = (decimal?)zero;

但我认为你片段中的“0”不是“十进制(decimal)”类型。

我还不确定,因为这会得到相同的异常。

        int test=0;
        object zero = test;
        decimal? dec = (decimal?)zero;

我的问题最初来自以下方法:public TResult Convert(object value) { try { return (TResult)value; } catch (InvalidCastException) { return default(TResult); } }当调用以下代码时,该方法返回null: Convert<decimal?>(0);我无法对TResult做出任何假设,也不知道实际参数是什么。这就是为什么我不能使用Convert.To...()的好处。 - Przemaas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接