题
我有一个 IDataRecord reader
我正在检索小数,如下所示:
decimal d = (decimal)reader[0];
由于某种原因,这会引发无效的强制转换异常,指出“指定的强制转换无效”。
当我做 reader[0].GetType()
它告诉我它是一个 Int32。据我所知,这应该不是问题......
我已经通过这个片段进行了测试,效果很好。
int i = 3750;
decimal d = (decimal)i;
这让我摸不着头脑,想知道为什么它无法将读取器中包含的 int 拆箱为十进制。
有谁知道为什么会发生这种情况?我缺少什么微妙的东西吗?
解决方案
您只能将值类型取消装箱为其原始类型(以及该类型的可为空版本)。
顺便说一句,这是有效的(只是两行版本的简写):
object i = 4;
decimal d = (decimal)(int)i; // works even w/o decimal as it's a widening conversion
对于这背后的原因请阅读此内容 埃里克·利珀特的博客条目:代表和身份
就我个人而言,我将强制转换语法完成的操作分为四种不同类型的操作(它们都有不同的 IL 指令):
- 拳击(
box
IL指令)和拆箱(unbox
IL指令) - 通过继承层次结构进行转换(例如
dynamic_cast<Type>
在 C++ 中,使用castclass
IL指令验证) - 原始类型之间的转换(例如
static_cast<Type>
在 C++ 中,有大量用于基本类型之间不同类型转换的 IL 指令) - 调用用户定义的转换运算符(在 IL 级别,它们只是对适当的方法的调用)
op_XXX
方法)。
其他提示
有在铸造int
到decimal
没有问题的,但是当你拆箱一个目的必须使用的确切类型,所述对象包含。
要拆箱int
值成decimal
值,则第一拆箱它作为int,然后将它转换为十进制:
decimal d = (decimal)(int)reader[0];
在IDataRecord接口还具有用于取消装箱的值的方法:
decimal d = (decimal)reader.GetInt32(0);
下面是一个简单的解决方案。它负责拆箱,然后浇铸成十进制。工作对我罚款。
decimal d = Convert.ToDecimal(reader[0]); // reader[0] is int
迈赫达德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?
不隶属于 StackOverflow