尝试从ExecuteScalar()获取值时抛出exception

在下面的代码中,语句1抛出了转换exception。 我想知道为什么不拆箱?
声明2工作正常,但我想知道为什么第一个是错的?

using (IDbCommand command = connection.CreateCommand()) { command.CommandText = string.Format("SELECT COUNT(1) FROM {0}", tableName); int count = (int)command.ExecuteScalar(); //statement 1 } //int count = Convert.ToInt32(command.ExecuteScalar()); //statement 2 

叹息,执行标量会返回一个long / int64,当你编写SQL命令时,你知道返回值将是一个计算的整数(SELECT COUNT(…,也是SELECT MAX(…)

忽略其他建议,你需要的只是一个演员。 (没有这些命令永远不会返回一个字符串,即“42”)

 int count = (int)(long)command.ExecuteScalar(); 

或者如果担心大数字

 long count = (long)command.ExecuteScalar(); 

除非出于一些奇怪的原因,你无法控制正在执行的SQL语句,为什么复杂化与转换或装箱/拆箱有关。 很好的人,KISS,代码臃肿,……然后回答这个问题。

如果数据库字段确实是32位有符号整数,则只能转换为int。 如果它很长和/或未签名,则演员表将失败。

由于类型不太可能改变,您可以拆分执行和强制转换,并在强制转换之前设置断点以查看正确的类型。

铸造和转换不是一回事。 转换为int告诉编译器从ExecuteScalar返回的数据已经是int并且应该放入int变量。

转换它将尝试从ExecuteScalar返回的数据(无论数据类型如何)并尝试将其转换为int。

一个常见示例是您的查询返回字符串“42”。 您不能将“42”转换为int,因为它是一个字符串,但您可以转换它。

原因是盒装T只能拆箱到TNullable 。 你的情况下的数字结果恰好是一个已经被装箱作为objectlong ,所以当你使用一个强制转换时,它只对强制转换为long而不是int。 即使你有一个long你可以将它转换为int

有关更多讨论,请参见http://blogs.msdn.com/b/ericlippert/archive/2009/03/19/representation-and-identity.aspx 。

根据SqlCommand.ExecuteScalar方法文档,如果结果为空,则返回null。 你不能将null转换为int。

但是根据我的经验,它也可能在某些情况下返回Decimal类型。 但是这个页面上没有记录。 所以使用Convert.ToInt32是一个更安全的选择。

我详细说明了迪伦史密斯和达卡拉。 它与装箱和拆箱有关。 将您的代码更改为:

 using (System.Data.IDbCommand command = connection.CreateCommand()) { command.CommandText = string.Format("SELECT COUNT(1) FROM {0}", tableName); object count = command.ExecuteScalar(); System.Diagnostics.Trace.WriteLine(count.GetType()); int iCount = (int)count; //statement 1 } 

count的运行时间肯定不是int 。 这就是你得到InvalidCastException的原因。 取消装箱值类型时,必须将其拆分为变量的实际类型。 只有在取消装箱后才可以转换为int

请记住,语句1在这段代码中仍然失败,但您现在可以确定返回标量的实际类型。