关于c#:为什么我不能将int取消装箱作为小数?

Why can't I unbox an int as a decimal?

我有一个IDataRecord reader,我从以下内容中提取小数:

1
decimal d = (decimal)reader[0];

出于某种原因,这会引发一个无效的强制转换异常,表示"指定的强制转换无效"。

当我这样做时,它告诉我它是一个整数。据我所知,这不应该是个问题……

我用这段代码测试了这一点,效果很好。

1
2
int i = 3750;
decimal d = (decimal)i;

这让我抓耳挠腮,想知道为什么它不能将读卡器中包含的int作为一个十进制值拆封。

有人知道为什么会发生这种情况吗?有什么我不知道的吗?


只能将值类型取消绑定到其原始类型(以及该类型的可空版本)。

顺便说一下,这是有效的(只是两行版本的简写):

1
2
object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion

出于这个原因,阅读这篇埃里克·利珀特的博客文章:代表性和身份

就我个人而言,我将通过强制转换语法完成的操作分为四种不同的操作类型(它们都有不同的IL指令):

  • 装箱(boxil指令)和拆箱(unboxil指令)
  • 通过继承继承(如C++中的EDOCX1 2),使用EDCOX1×3的IL指令进行验证
  • 在原始类型之间进行转换(如C++中的EDCOX1×4),对于原始类型之间的不同类型的转换,有很多IL指令。
  • 调用用户定义的转换运算符(在IL级别,它们只是对适当的op_XXX方法的方法调用)。
    • 从某种意义上说,拆箱和强制转换在语法上看起来是相同的,这是很遗憾的,因为它们是非常不同的操作。
    • 谢谢我爸爸。你的解释和链接到埃里克的博客是非常有帮助的。
    • 谢谢您!这使我陷入了困境。
    • 但如果值有时是一个整数,但有时是一个真正的小数。首先强制转换为int将丢失十进制值。如果您期望一个双精度,那么通过验证源是否给您一个多字节来确保。否则,你会有副作用,会让最终用户把头发刮出来,然后戳到你的眼球。回答不错,但建议却很糟糕-应该是-1
    • @普普姆金:你似乎错过了整个要点。你不能直接用(int)a铸造object a = (decimal)5;。它会抛出一个InvalidCastException
    • 如果值是5.00,那么(decimal)5.00是有效的,是吗?你能保证不会是5点吗?如果可以的话,就不需要将它强制转换为十进制。除非我真的弄错了什么?
    • @ppumkin这个例子不需要为这件事向decimal或任何其他类型的对象进行强制转换。它是关于将装箱值直接强制转换为另一个类型的可能性,说明装箱/取消装箱转换和简单的原始类型转换之间的细微差别,尽管它们都使用相同的强制转换语法。
    • 好吧-我答应了。我有一个问题,我想总是有双倍的,即使它是盒装的国际。我谷歌,并得到了这个答案。我只需要确保它被装箱为双,以避免这个问题,我有。谢谢你解释+1


    这是一个简单的解决方案。它负责拆箱,然后转换为小数。对我来说工作很好。

    1
    decimal d = Convert.ToDecimal(reader[0]);  // reader[0] is int

    • 这就是我的答案——我的返回类型似乎是由返回的数字的大小动态决定的。它处理了将装箱的int或装箱的decimal转换为未装箱的decimal的问题。


    int强制转换为decimal时没有问题,但是在解除对象绑定时,必须使用对象所包含的确切类型。

    要将int值取消装箱为decimal值,首先将其作为int取消装箱,然后将其转换为十进制:

    1
    decimal d = (decimal)(int)reader[0];

    IDataRecord接口还具有取消绑定值的方法:

    1
    decimal d = (decimal)reader.GetInt32(0);

    • 谢谢你的回答太夸张了……这很有帮助。
    • 但如果值有时是一个整数,但有时是一个真正的小数。首先强制转换为int将丢失十进制值。如果您期望一个双精度,那么通过验证源是否给您一个多字节来确保。否则,你会有副作用,会让最终用户把头发刮出来,然后戳到你的眼球。回答不错,但建议却很糟糕-应该是-1
    • @普普姆金:对不起,如果你误解了答案。它不是投射到int,然后投射到decimal,它是解开int,然后投射到decimal。拆箱价值作为一个int永远不会使它失去任何东西,因为如果它实际上不是一个int,就不可能拆箱它作为一个int开始。


    阿夫沙里说:

    You can only unbox a value type to its original type (and the nullable
    version of that type).

    要认识到的是,铸造和拆箱之间有区别。杰里耶瓦尔说得很好

    In a sense it's a shame that unboxing and casting syntactically look
    identical, since they are very different operations.

    铸造:

    1
    2
    int i = 3750; // Declares a normal int
    decimal d = (decimal)i; // Casts an int into a decimal > OK

    装箱/拆箱:

    1
    2
    object i = 3750; // Boxes an int ("3750" is similar to"(int)3750")
    decimal d = (decimal)i; // Unboxes the boxed int into a decimal > KO, can only unbox it into a int or int?