63

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

decimal d = (decimal)reader[0];

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

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

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

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

这让我摸不着头脑,想知道为什么它无法将阅读器中包含的 int 拆箱为小数。

有谁知道为什么会发生这种情况?我错过了什么微妙的东西吗?

4

4 回答 4

83

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

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

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

对于这背后的原因,请阅读此Eric Lippert 的博客条目:表示和身份

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

  1. 装箱(boxIL 指令)和拆箱(unboxIL 指令)
  2. 通过继承层次进行强制转换(如dynamic_cast<Type>在 C++ 中,使用castclassIL 指令进行验证)
  3. 原始类型之间的转换(如static_cast<Type>在 C++ 中,有大量 IL 指令用于原始类型之间的不同类型的转换)
  4. 调用用户定义的转换运算符(在 IL 级别,它们只是对适当op_XXX方法的方法调用)。
于 2009-07-06T01:52:48.777 回答
15

int强制转换to没有问题decimal,但是当您拆箱对象时,您必须使用该对象包含的确切类型。

要将int值拆箱为decimal值,首先将其拆箱为 int,然后将其转换为十进制:

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

IDataRecord 接口还具有拆箱值的方法:

decimal d = (decimal)reader.GetInt32(0);
于 2009-07-06T01:55:25.840 回答
15

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

decimal d = Convert.ToDecimal(reader[0]);  // reader[0] is int
于 2015-12-28T20:59:42.470 回答
3

Mehrdad Afshari 说:

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

要意识到的是cast 和 unboxing 之间是有区别的。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?
于 2011-10-04T04:35:56.637 回答