C# 从int转换为long抛出异常

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

我有一个有两列的表(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.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。。作用
    • 备注部分说明:

      不进行任何转换;因此,检索到的数据必须已经是64位有符号整数

      顺便说一下:如果您的值可以为null,请不要忘记调用IsDBNUll

      是否确定检索到的数据是数据库中的bigint?如果是int或nchar/nvarchar,则应使用相应的函数并将其强制转换或解析为System.Int64

      有些人建议提高代码的健壮性

      • 使用SqlDataReader[columnName]而不是GetInt64。这将为您提供原始类型的对象,该对象最有可能转换为您的long
      • 使用列名而不是列号可以提高代码的稳定性。如果在查询中对列进行了重新排序,或者从查询中添加或删除了不同的列,则该方法仍然有效
      • 如果你真的想坚持使用GetInt。。。函数,使用SqlDataReader.GetOrdinal(列名)获取列号
      • 分配前,请使用SqlDataReader.GetFieldType检查列的类型并使用相应的GetInt。。作用

      您需要通过
      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)