C# 从int转换为long抛出异常
我有一个有两列的表(string&int)。int列的当前值为C# 从int转换为long抛出异常,c#,sql-server-2012,C#,Sql Server 2012,我有一个有两列的表(string&int)。int列的当前值为-1 使用SQLDataReader我正在读取此表中的行: public class MyObject { public string Name; public long Number; } using (SqlDataReader dataReader = command.ExecuteReader()) { MyObject o = new MyObject() while (dataReader
-1
使用SQLDataReader
我正在读取此表中的行:
public class MyObject
{
public string Name;
public long Number;
}
using (SqlDataReader dataReader = command.ExecuteReader())
{
MyObject o = new MyObject()
while (dataReader.Read())
{
o.Name= dataReader.GetString(0);
o.Number = dataReader.GetInt64(1);
}
}
然而,当我阅读编号
列时,我得到了一个无效的castexception
。我在这里遗漏了什么?评论部分指出:
不进行任何转换;因此,检索到的数据必须已经是64位有符号整数
顺便说一下:如果您的值可以为null,请不要忘记调用IsDBNUll
是否确定检索到的数据是数据库中的bigint?如果是int或nchar/nvarchar,则应使用相应的函数并将其强制转换或解析为System.Int64
有些人建议提高代码的健壮性
- 使用SqlDataReader[columnName]而不是GetInt64。这将为您提供原始类型的对象,该对象最有可能转换为您的long
- 使用列名而不是列号可以提高代码的稳定性。如果在查询中对列进行了重新排序,或者从查询中添加或删除了不同的列,则该方法仍然有效
- 如果你真的想坚持使用GetInt。。。函数,使用SqlDataReader.GetOrdinal(列名)获取列号
- 分配前,请使用SqlDataReader.GetFieldType检查列的类型并使用相应的GetInt。。作用
- 使用SqlDataReader[columnName]而不是GetInt64。这将为您提供原始类型的对象,该对象最有可能转换为您的long
- 使用列名而不是列号可以提高代码的稳定性。如果在查询中对列进行了重新排序,或者从查询中添加或删除了不同的列,则该方法仍然有效
- 如果你真的想坚持使用GetInt。。。函数,使用SqlDataReader.GetOrdinal(列名)获取列号
- 分配前,请使用SqlDataReader.GetFieldType检查列的类型并使用相应的GetInt。。作用
- 备注部分说明:
不进行任何转换;因此,检索到的数据必须已经是64位有符号整数
顺便说一下:如果您的值可以为null,请不要忘记调用IsDBNUll
是否确定检索到的数据是数据库中的bigint?如果是int或nchar/nvarchar,则应使用相应的函数并将其强制转换或解析为System.Int64
有些人建议提高代码的健壮性
GetInt32
将其作为int
读取。您不需要将其强制转换为long
,因为这可以通过运行时的安全性隐式完成
运行时不允许您先将对象
反装箱为对象
的正确内部数据类型,然后再强制转换为下一个数据类型,就从对象
反装箱到另一个数据类型。这种怪癖与数据读取器无关:
static void Main(string[] args)
{
int i = 1;
object o = i;
long l = (long)o; // invalid cast, trying to unbox to something other than the original type
l = (long)(int)o; // No invalid cast, un-boxed to int then cast to long.
}
特别是对于SqlDataReader
,因为您的基础类型不是Int64
,所以它会在内部尝试将box直接解算到错误的类型:
internal Int64 Int64 {
get {
ThrowIfNull();
if (StorageType.Int64 == _type) {
return _value._int64;
}
return (Int64)this.Value; // anything else we haven't thought of goes through boxing.
}
// set excluded for brevity
}
取自
TL;博士按照文档中的说明(根据HaraldDutch的回答)阅读正确的预期类型。您需要通过
GetInt32
将其作为int
阅读。您不需要将其强制转换为long
,因为这可以通过运行时的安全性隐式完成
运行时不允许您先将对象
反装箱为对象
的正确内部数据类型,然后再强制转换为下一个数据类型,就从对象
反装箱到另一个数据类型。这种怪癖与数据读取器无关:
static void Main(string[] args)
{
int i = 1;
object o = i;
long l = (long)o; // invalid cast, trying to unbox to something other than the original type
l = (long)(int)o; // No invalid cast, un-boxed to int then cast to long.
}
特别是对于SqlDataReader
,因为您的基础类型不是Int64
,所以它会在内部尝试将box直接解算到错误的类型:
internal Int64 Int64 {
get {
ThrowIfNull();
if (StorageType.Int64 == _type) {
return _value._int64;
}
return (Int64)this.Value; // anything else we haven't thought of goes through boxing.
}
// set excluded for brevity
}
取自
TL;博士按照文档中的说明(根据HaraldDutch的回答)阅读正确的预期类型。确保您试图获取的值是数据库中的bigint。
BIGINT相当于Int64(在C#中很长)。如果它不是BIGINT,请尝试使用Convert.ToInt64()确保您尝试获取的值是数据库中的BIGINT。
BIGINT相当于Int64(在C#中很长)。如果它不是BIGINT,请尝试使用Convert.ToInt64()确定以得出正确的结论。您的列数据类型为int not bigint,因此无法通过.GetInt64()调用它,因为它正在取消绑定并 无法取消选中Int32->Int64 正如@Adam Houldsworth提到的- 阅读所给予的,而不是你想要的 要解决问题,只需将GetInt64()切换到GetInt32()。见下文:
using (SqlDataReader dataReader = command.ExecuteReader())
{
MyObject o = new MyObject()
while (dataReader.Read())
{
o.Name= dataReader.GetString(0);
o.Number = dataReader.GetInt32(1); // safe implicitly cast no need to make it manually
}
}
如果您不知道确切的底层数据类型,您可以用另一种方法。请参阅下面的代码:
using (SqlDataReader dataReader = command.ExecuteReader())
{
MyObject o = new MyObject()
while (dataReader.Read())
{
o.Name = dataReader.GetString(0);
var number = dataReader.GetValue(1);
try
{
o.Number = Convert.ToInt64(number);
}
catch(InvalidCastException)
{
Throw new Exception("Underlying DataType is not convertable to int 64.");
}
}
}
好的,我来做出正确的结论。您的列数据类型为int not bigint,因此无法通过.GetInt64()调用它,因为它正在取消绑定并 无法取消选中Int32->Int64 正如@Adam Houldsworth提到的- 阅读所给予的,而不是你想要的 要解决问题,只需将GetInt64()切换到GetInt32()。见下文:
using (SqlDataReader dataReader = command.ExecuteReader())
{
MyObject o = new MyObject()
while (dataReader.Read())
{
o.Name= dataReader.GetString(0);
o.Number = dataReader.GetInt32(1); // safe implicitly cast no need to make it manually
}
}
如果您不知道确切的底层数据类型,您可以用另一种方法。请参阅下面的代码:
using (SqlDataReader dataReader = command.ExecuteReader())
{
MyObject o = new MyObject()
while (dataReader.Read())
{
o.Name = dataReader.GetString(0);
var number = dataReader.GetValue(1);
try
{
o.Number = Convert.ToInt64(number);
}
catch(InvalidCastException)
{
Throw new Exception("Underlying DataType is not convertable to int 64.");
}
}
}
如果您想将SQLDataReader对象从(对象{int})取消装箱到long,您应该知道,没有直接的方法。例如,此代码
long _result = (long)(sqlDR["IntTypeField"] ?? 0L);
将生成“System.InvalidCastException”。
你应该使用更全面的功能,像这样
public static T NvlO<T>(object a, T b)
{
if (a == null)
return b;
else
{
var lSrcType = a.GetType();
var lDestType = typeof(T);
if (lDestType.IsValueType && lDestType.IsAssignableFrom(lSrcType))
return (T)a;
var lDestTC = TypeDescriptor.GetConverter(typeof(T));
if (lDestTC.CanConvertFrom(lSrcType))
return (T)lDestTC.ConvertFrom(a);
else
{
var lSrcTC = TypeDescriptor.GetConverter(lSrcType);
String lTmp = lSrcTC.ConvertToInvariantString(a);
return (T)lDestTC.ConvertFromInvariantString(lTmp);
}
}
}
公共静态tNVLO(对象a、tB)
{
if(a==空)
返回b;
其他的
{
var lSrcType=a.GetType();
var lDestType=typeof(T);
if(lDestType.IsValueType&&lDestTy)