取消装箱 -1 并使用泛型转换为 Nullable<int> 会产生 InvalidCastException

Unboxing -1 and casting to Nullable<int> using generics yields InvalidCastException

this SO post 中,我找到了一个通用扩展方法,如果 SqlDataReader 读取的值是 nullDBNull.Value,则该方法 returns 是默认值,否则正确转换的值。我是这样实现的:

public static T GetValueOrDefault<T>(this SqlDataReader reader, string columnName, T defaultValue = default(T))
{
  object val = reader[columnName];
  if (val == null || val == DBNull.Value)
  {
    return defaultValue;
  }

  return (T)val;
}

上面链接的 post 中的方法下面提到的示例没有使用正确的语法,但仍然建议这也适用于可空类型,例如 int?.

但是,我从数据库中读取了一个可为空的 int 列,如下所示:

MyProperty = reader.GetValueOrDefault<int?>("SomeColumnName")

调试模式显示 val-1Tint?,但我得到了 InvalidCastException。从 this post 我认为这是因为不能在单个操作中执行拆箱和转换(val 是类型 object 持有 short 值),但我能做什么使它在我的情况下起作用?由于它是一种通用方法,我不知道如何在进行转换之前将其手动拆箱。

要获得真正好的答案,您需要 post a good, minimal, complete code example

如果转换为 int 失败,则装箱值不是 int。您应该能够在调试器中看到它实际上是什么。

也就是说,Convert class 在转换方面要复杂得多;转换将需要 精确 匹配,即盒装值必须是 int(文字 -1 将是 int,但在您的如果值来自谁知道哪里,很容易是 shortlong 或其他任何东西)。

所以不是演员,而是一个电话,例如Convert.ToInt32() 会更好。

在您的情况下,使用泛型方法(即编译时类型未知),Convert.ChangeType() 方法可能更合适:

public static T GetValueOrDefault<T>(this SqlDataReader reader, string columnName, T defaultValue = default(T))
{
  object val = reader[columnName];
  if (val == null || val == DBNull.Value)
  {
    return defaultValue;
  }

  return (T)Convert.ChangeType(val, typeof(T));
}