在C#中,Int64和long不是等价的吗?

33
我一直在使用 SqlCeConnection 在 C# 中处理 SQL 和数据库。我一直使用ExecuteReader 读取结果,并使用 BigInt 值作为记录 ID,将其读入 Long 中。
今天我在处理基于 COUNT 的语句时遇到了问题 ("SELECT COUNT(*) FROM X") ,并使用 ExecuteScalar 读取单个值的结果。
然而,我遇到了一个问题。我似乎无法将这些值存储到 Long 数据类型中,而我到目前为止一直在使用它们。我只能将它们存储到 Int64 中。
我一直使用 BigInt 作为记录 ID 来获取最大潜在记录数。
BigInt 8 字节因此是一个 Int64。难道 Long 不等于 Int64,因为两者都是有符号的 64 位整数吗?
因此,为什么我不能将 Int64 强制转换为 Long?
long recordCount =0;

recordCount = (long)selectCommand.ExecuteScalar();

错误信息为:

指定的强制类型转换无效。

我可以将 BigInt 转换成 Long,这不是问题。 但我无法将 SQL COUNT 转换成 long。

COUNT 返回 Int(Int32),所以问题实际上是将 Int32 强制转换成 long。


recordCount 定义为什么? - Massif
1
@BoltClock:你可以直接将int强制转换为long(实际上,你甚至不需要强制转换,因为有一个隐式转换可用)。 OP的问题在于,您无法将装箱的int解箱为long。装箱的值类型(通常)需要解箱为完全相同的类型。 - LukeH
2个回答

36

longInt64在.NET中的别名; 在C#中,它只是一个别名。您的问题是将返回值强制转换为long,除非我们确切知道查询返回的类型,否则我们不知道为什么会出现错误。SQL BigInt必须可以转换为long

如果返回的是COUNT(*),那么它是Int32。 您需要使用Convert类:

long l = Convert.ToInt64(selectCommand.ExecuteScalar());

3
没问题,我会尽力进行翻译。+1,你说得对,“COUNT”返回一个32位整数,我相信这就是当OP试图将该“int”取消装箱为“long”时出现问题的根源。虽然没有必要使用显式的“Convert.ToInt64”,但是“long l = query.ExecuteScalar();”完全可以正常工作,因为“int”可以隐式地分配给“long”。 - LukeH
3
long l = query.ExecuteScalar() 在编译时会失败,因为无法隐式将对象转换为长整型。同样,long l = (long)query.ExecuteScalar() 在运行时会失败,因为该转换无效。使用 Convert.ToInt64 将对象转换为 Int64 或长整型。 - anothershrubery
@anothershrubery:糟糕,你是对的:long l = (int)query.ExecuteScalar(); 可以解决问题(虽然我不确定它是否比使用 Convert.ToInt64 更易读)。 - LukeH
@Aliostad 我可以将 BigInt 存储到 long 中,没有问题。但是我无法将 COUNT 结果存储为 long,会出现 {"Specified cast is not valid."} 错误。不过,我可以将其转换为 int64,这应该与 long 相同? - user427165
@andicrook:如果要将其存储在long/Int64变量中,则需要执行以下操作之一:long l = Convert.ToInt64(selectCommand.ExecuteScalar());,就像Aliostad上面的答案一样,或者long l = (int)selectCommand.ExecuteScalar(); - LukeH
显示剩余3条评论

6
如果您认为计数将溢出int/Int32,您应该在SQL中使用COUNT_BIG(),因为它具有正确的返回类型。
关于为什么强制类型转换不起作用,我不确定。以下是C#代码:
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
long lCount = (long)cmd.ExecuteScalar();
Int64 iCount = (Int64)cmd.ExecuteScalar();

编译成以下IL代码:

L_0000: nop 
L_0001: newobj instance void [System.Data]System.Data.SqlClient.SqlCommand::.ctor()
L_0006: stloc.0 
L_0007: ldloc.0 
L_0008: callvirt instance object [System.Data]System.Data.Common.DbCommand::ExecuteScalar()
L_000d: unbox.any int64
L_0012: stloc.1 
L_0013: ldloc.0 
L_0014: callvirt instance object [System.Data]System.Data.Common.DbCommand::ExecuteScalar()
L_0019: unbox.any int64
L_001e: stloc.2 
L_001f: ret 

也就是说,它们似乎编译成相同的代码。

COUNT_BIG()也不会转换为long。当一个long是int64时,COUNT和COUNT_BIG将转换为int64,但不会转换为long。为什么? - user427165
@andicrook - 你能否将你的代码反编译成IL版本,针对长整型和Int64版本,就像我上面所做的那样,并将你的结果添加到问题中吗? - Damien_The_Unbeliever
我的错,我没有重新编译,仍然不起作用。我认为SQL Compact Edition不支持COUNT_BIG。{"该函数未被SQL Server Compact Edition所识别。[函数名称=COUNT_BIG,数据类型(如果已知)=]"} - user427165
1
@andicrook - COUNT() 的返回类型是 int/Int32,因此将其存储在 int/Int64 中并没有任何好处。您是正确的,紧凑模式不支持 COUNT_BIG(),但我认为这是您第一次提到这是您的目标 SQL Server。 - Damien_The_Unbeliever
@ Damien_The_Unbeliever 我确实指定了我正在使用紧凑版,我是通过SqlCeConnection(Ce =紧凑版)而不是SqlConnection。你是对的,我没有意识到COUNT的限制,因此无论如何都无法从int64或long中获得好处。需要查找此版本每个表的最大记录数,并可能将所有内容降至int32。但是,我将稍后添加对完整SQL服务器的支持,因此了解COUNT_BIG很有用。谢谢。 - user427165

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