为什么我不能像这样将MSSQL中的smallint转换为int:int x = (int)dt.Rows[x]["smallIntColumn"]?

6

我想请您解释一下这个问题——问题基本上已经说明了一切,但这里有一些额外的信息:

只是想要一个关于这个的解释。与其相关的问题已经被解决了,但是现在我们需要更多的背景知识来完全理解。

//this line works OK
int i = Convert.ToInt32(dt.Rows[x]["SmallintColumnName"]);

//this line errors out
int j = (int)dt.Rows[x]["SmallintColumnName"];

我觉得这很奇怪,但我猜这样做有其合理的论据。
谢谢。
编辑: 嗨@Damien_The_Unbeliever- 这是一个无效的转换异常 - 指定的转换无效。 我想我需要阅读一下装箱和拆箱。我以为两个都可以工作。 现在我刚刚尝试了:
int k = (Int32)r_dtAttribute.Rows[x]["CultureId"];

这也会出现同样的无效类型转换异常 - 所以有人能告诉我实际上它们之间的区别是什么吗?

//fails
int k = (Int32)r_dtAttribute.Rows[x]["CultureId"];

并且

//works
int i = Convert.ToInt32(dt.Rows[x]["SmallintColumnName"]);

Convert.ToInt32函数与(Int32)强制类型转换有什么不同?

谢谢


5
错误在哪里?通常他们会很好地告诉你为什么他们做不了。 - Chris
1
可能为空值时,Convert.ToInt32 返回 0,但是 (int) 会引发异常。 - Grundy
装箱和拆箱:装箱和拆箱是指将值类型转换为对象类型,而拆箱则是将对象类型转换为值类型。如果试图将引用类型拆箱为不兼容的值类型,则会导致InvalidCastException异常。 - Damien_The_Unbeliever
@Damien_The_Unbeliever 你为什么认为 OP 有 InvalidCastException? :-) - Grundy
@Grundy - 经验。数据库类型为 smallint,ADO 永远不会返回装箱的 int32。因此,(int) 永远不起作用,无论特定行是否返回 null 或实际值。 - Damien_The_Unbeliever
大家好 - 感谢你们的帮助 - @Damien_The_Unbeliever,这是一个 InvalidCastException - 我刚刚在关于(Int32)的问题上又添加了一个测试 - 有人能解释一下吗? - Percy
1个回答

9

dt.Rows[x]["SmallintColumnName"]将返回一个object。实际上,数据库返回的值已经被ADO.Net转换为Int161,但由于表达式的返回值是object,所以该值被装箱

我在评论中链接了一篇关于装箱和拆箱的文章。你的表达式:

int j = (int)dt.Rows[x]["SmallintColumnName"];

尝试从对象中解压缩一个值的操作。但是装箱和拆箱的规则指出,你只能拆箱与装箱类型完全相同的值(除了一些关于枚举及其基础类型的奇怪规则,如果我没记错的话)。但由于我们知道这里有一个装箱的Int16值,所以会得到一个InvalidCastException异常。
你可以做的是:
int j = (int)(Int16)dt.Rows[x]["SmallintColumnName"];

甚至只是:

int j = (Int16)dt.Rows[x]["SmallintColumnName"];

我们首先打开Int16值的包装盒,然后明确地(第一个示例)或隐式地(第二个示例)将Int16强制转换为Int32。令人遗憾的是,类型转换和拆箱看起来完全一样。

Convert.ToInt32(object)是一个完全不同的东西,支持各种转换。它实际上是将参数强制转换为IConvertible接口(Int16支持),然后在Int16上调用ToInt32方法。反过来,它又会切换回从装箱的Int16到普通的Int16,最终被隐式转换成Int32。真是神奇。


1我尝试着在整个答案中使用一致的类型名称,但请注意shortInt16是完全相同的类型。intInt32也是相同的类型。因此,将您的尝试从(int)更改为(Int32)实际上并没有导致编译代码发生任何变化。


非常棒的答案 - 非常感谢!!! - 还有一个问题 - 我想我可以使用100,000个“unboxes”的循环和相同数量的Convert.ToInt32(object)调用来测试这个,但如果您能够立即知道,那就太好了 - 在速度方面,哪种方法具有最佳性能,我认为(int)(Int16)方法是最好的,因为我们明确告诉它要做什么,而不仅仅是说“在这里,找出是否可以完成”。再次感谢。 - Percy
@Rick - 我从未测试过,也必须执行类似于您建议的测试。但我永远不会做那个测试。我有强烈的直觉,将结果转换为 int 的努力绝对被查询数据库和(如果不是本地)网络开销所淹没。在不了解它将提供任何好处的情况下,请勿尝试优化任何内容。 - Damien_The_Unbeliever
你说得对!!!我一直告诉自己“不要试图优化不需要优化的代码!”但是我总是忘记了,陷入其中!再次感谢你的帮助 :) - Percy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接