为什么我不能将int取消装入十进制?

时间:2009-07-06 01:49:19

标签: c# decimal int unboxing

我有IDataRecord reader我正在检索小数,如下所示:

decimal d = (decimal)reader[0];

由于某种原因,这会抛出一个无效的强制转换异常,说“指定的强制转换无效。”

当我reader[0].GetType()时,它告诉我它是Int32。据我所知,这应该不是问题......

我已经通过这个片段进行了测试,这个片段效果很好。

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

这让我头疼不已,想知道为什么它没有将读取器中包含的int解包为十进制。

有谁知道为什么会这样?我有什么微妙的东西吗?

4 个答案:

答案 0 :(得分:78)

您只能将值类型取消装箱为其原始类型(以及该类型的可空版本)。

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

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

由于这背后的原因,请阅读此Eric Lippert's blog entry: Representation and Identity

就个人而言,我将演员语法完成的事情分为四种不同类型的操作(它们都有不同的IL指令):

  1. 拳击(box IL指令)和拆箱(unbox IL指令)
  2. 强制转换inhertiance层次结构(如C ++中的dynamic_cast<Type>,使用castclass IL指令进行验证)
  3. 在原始类型之间进行转换(如C ++中的static_cast<Type>,对于基本类型之间的不同类型的转换,有大量的IL指令)
  4. 调用用户定义的转换运算符(在IL级别,它们只是对相应op_XXX方法的方法调用)。

答案 1 :(得分:14)

int转换为decimal没有问题,但是当您取消装箱对象时,必须使用该对象包含的确切类型。

要将int值取消装入decimal值,首先将其取消装箱为int,然后将其转换为小数:

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

IDataRecord接口还具有取消装箱值的方法:

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

答案 2 :(得分:14)

这是一个简单的解决方案。它负责拆箱,然后转换为十进制。为我工作得很好。

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

答案 3 :(得分:3)

Mehrdad Afshari说:

  

您只能将值类型拆分为其原始类型(以及可为空的类型)   那种类型的版本。)

要意识到的是在投射和拆箱之间存在差异。 jerryjvl有一个很好的评论

  

从某种意义上说,拆箱和转换语法是一种耻辱   相同,因为它们是非常不同的操作。

铸造:

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

拳击/开箱:

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?