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

mez*_*oid 61 c# int unboxing decimal

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

decimal d = (decimal)reader[0];
Run Code Online (Sandbox Code Playgroud)

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

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

我已经通过这个片段测试了这个,它运行得很好.

int i = 3750;
decimal d = (decimal)i;
Run Code Online (Sandbox Code Playgroud)

这让我头疼不已,想知道为什么它没有将读取器中包含的int取消装箱作为小数.

有谁知道为什么会这样?有什么微妙的我不见了吗?

Meh*_*ari 80

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

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

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

由于这背后的原因,请阅读Eric Lippert的博客文章:Representation and Identity

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

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

  • 从某种意义上说,拆箱和转换在语法上看起来完全相同是一种耻辱,因为它们是非常不同的操作. (21认同)
  • @ppumkin这个例子不是**需要**转换为`decimal`或任何其他类型的东西.它是关于将盒装值直接转换为另一种类型的可能性,展示了装箱/拆箱转换与简单原始类型转换之间的细微差别,尽管它们都使用相同的转换语法. (2认同)

Guf*_*ffa 15

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

要将int值拆分为decimal值,首先将其解压缩为int,然后将其转换为十进制:

decimal d = (decimal)(int)reader[0];
Run Code Online (Sandbox Code Playgroud)

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

decimal d = (decimal)reader.GetInt32(0);
Run Code Online (Sandbox Code Playgroud)


Sag*_*gar 15

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

decimal d = Convert.ToDecimal(reader[0]);  // reader[0] is int
Run Code Online (Sandbox Code Playgroud)