【问题标题】:Why can't I unbox an int as a decimal?为什么我不能将 int 拆箱为小数?
【发布时间】:2010-11-08 06:40:03
【问题描述】:

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

decimal d = (decimal)reader[0];

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

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

我已经通过这个 sn-p 进行了测试,效果很好。

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

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

有谁知道为什么会发生这种情况?有什么我遗漏的微妙之处吗?

【问题讨论】:

标签: c# decimal int unboxing


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 从某种意义上说,拆箱和强制转换在语法上看起来相同是一种耻辱,因为它们是非常不同的操作。
  • 谢谢梅尔达德。您对 Eric 博客的解释和链接非常有帮助。
  • 谢谢!这让我陷入了困境。
  • 但是如果该值有时是一个完整的数字,但有时是一个真正的小数。首先转换为 int 将丢失十进制值。如果您期望双倍,那么通过验证确保来源给您一个双倍。否则你会得到副作用,这会让最终用户刮掉他的头发,然后戳你的眼球。好的答案,但非常糟糕的建议 - 它值得 -1
  • @ppumkin 该示例不是关于需要强制转换为decimal 或任何其他类型。这是关于将装箱值直接转换为另一种类型的可能性,展示了装箱/拆箱转换和简单的原始类型转换之间的细微差别,尽管它们都使用相同的转换语法。
【解决方案2】:

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

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

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

IDataRecord 接口也有拆箱值的方法:

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

【讨论】:

  • 感谢您的回复 Guffa...非常有帮助。
  • 但是如果该值有时是一个完整的数字,但有时是一个真正的小数。首先转换为 int 将丢失十进制值。如果您期望双倍,那么通过验证确保来源给您一个双倍。否则你会得到副作用,这会让最终用户刮掉他的头发,然后戳你的眼球。好的答案,但非常糟糕的建议 - 它值得 -1
  • @ppumkin:如果您误解了答案,对不起。它不是先转换为int,然后再转换为decimal,而是拆箱int,然后再转换为decimal。将值拆箱为 int 永远不会让它丢失任何东西,因为如果它实际上不是 int 开始时,就不可能将其拆箱为 int
【解决方案3】:

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

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

【讨论】:

  • 这就是我的答案——我的返回类型似乎是由返回数字的大小动态决定的。这处理了将装箱的 int 或装箱的小数转换为未装箱的小数。
【解决方案4】:

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?

【讨论】:

    猜你喜欢
    • 2010-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 2013-01-15
    • 2012-12-30
    相关资源
    最近更新 更多