为什么我不能取消一个int作为小数?

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

 decimal d = (decimal)reader[0]; 

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

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

我已经testing了这个片段,这工作得很好。

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

这让我挠脑袋,想知道为什么它不能将读取器中包含的int作为十进制数来打开。

有谁知道为什么这可能会发生? 我错过了些微妙的东西吗?

您只能将值types取消为原始types(以及该types的可为空的版本)。

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

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

为此,请阅读Eric Lippert的博客文章:表示和身份

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

  1. 拳击( box IL指令)和拆箱( unbox IL指令)
  2. 通过inhertiance层次结构(如C ++中的dynamic_cast<Type> ,使用castclass IL指令进行validation)
  3. 在原始types之间进行转换(如C ++中的static_cast<Type> ,对于原始types之间的不同types的转换,有很多IL指令)
  4. 调用用户定义的转换运算符(在IL级别,他们只是方法调用适当的op_XXX方法)。

intdecimal是没有问题的,但是当你拆箱的时候,你必须使用对象所包含的确切types。

要将int值解包为一个decimal值,您首先将其解包为一个int,然后将其转换为十进制:

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

IDataRecord接口也有拆箱的方法:

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

这是一个简单的解决scheme。 它需要照顾拆箱,然后铸造到十进制。 为我工作得很好。

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

Mehrdad Afshari说:

您只能将值types取消为原始types(以及该types的可为空的版本)。

要实现的事情是铸造和拆箱是有区别的 。 杰里耶夫有一个很好的评论

从某种意义上说,拆箱和铸造在句法上看起来是完全相同的,因为它们是非常不同的操作。

铸件:

 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?