"无法将 DBNull 强制转换为其他类型的对象"

12
当我的网站到达以下代码段时,它会因为以下异常而崩溃:
System.InvalidCastException: 无法将对象从 DBNull 转换为其他类型。
为了简洁起见,我只展示相关代码(这是一个我收到的超过4000行的文件)。
if (dr["STAGE"] is DBNull)
{
    dto.Stage = 1; // This is the line throwing the exception, according to stack trace
}
else
{
    dto.Stage = Convert.ToInt32(dr["STAGE"]);
}

这里,dr 是一个DataRow对象,是查询数据库的结果,dto 是一个基本类,仅保留一些属性,其中dto.Stage是一个int成员。

我已经查看了其他具有相同错误消息的问题,但它们大多数似乎建议“检查是否为DBNull”,而我已经在这样做了。

那么有人能提出解决方案吗?


1
我不确定,但似乎错误是由 dto.Stage = Convert.ToInt32(dr["STAGE"]); 引起的,请尝试使用 DBNULL.value。 - Kamran Pervaiz
3
不要过于关注堆栈跟踪中的确切行号,因为这些数字可能会略有偏差,我经常看到这种情况。相反,建议您在调试器中设置断点运行代码,或者在尝试解决问题时添加额外的日志记录。请注意,在此过程中不要改变原来的意思。 - Marc Gravell
1
呵呵,我使用Dapper的原因就在于避免这些有趣的问题! - Marc Gravell
如果在尝试设置dto.Stage = 1时出现错误,那么dto可能为空吗? - tardomatic
我认为@MarcGravell说得有道理,如果在dto.Stage=1;之前加上throw,那么DBNull异常会在其他地方发生。 :| 该死的堆栈跟踪把我引入了错误的方向。 - TZHX
显示剩余5条评论
5个回答

5
请使用==代替is
if (dr["STAGE"] == DBNull.Value)
{

}

2

使用这种稍微更有效的方法

int stageOrdinal = dr.GetOrdinal("STAGE");
while (dr.Read()) {
     dto = new DataTransferObject();
     if (dr.IsDBNull(stageOrdinal)) {
         dto.Stage = 1;
     } else {
         dto.Stage = dr.GetInt32(stageOrdinal);
     }
     //TODO: retrieve other columns.
     dtoList.Add(dto);
}

通过索引访问列比通过名称访问列更快。可以使用DataReaderGetOrdinal方法检索列的索引。最好在循环之前完成此操作。


1

0
以下是一个可空数据类型的示例,您可以使用它来避免 DBNull 错误。 下面的示例不是您所遇到问题的真正解决方案,但它展示了如何解决该问题。可以将其视为学习钓鱼而不是得到一条鱼。 我从http://msdn.microsoft.com/en-us/library/1t3y8s4s.aspx中获取了这个示例。
class NullableExample
{
    static void Main()
    {
        int? num = null;
        if (num.HasValue == true)
        {
            System.Console.WriteLine("num = " + num.Value);
        }
        else
        {
            System.Console.WriteLine("num = Null");
        }

        // y is set to zero
        int y = num.GetValueOrDefault();

        // num.Value throws an InvalidOperationException if num.HasValue is false
        try
        {
            y = num.Value;
        }
        catch (System.InvalidOperationException e)
        {
            System.Console.WriteLine(e.Message);
        }
    }
}

0

@MarcGravell在他的评论中是正确的:

忽略堆栈跟踪中的确切行号;数字可能会有所偏差 - 我经常看到这种情况。使用调试器和断点运行它,或者在你解决问题时添加额外的日志记录。

@Sergey的答案完全是错误的。


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