C# System.InvalidCastException:无法将对象从DBNull强制转换为其他类型

C# System.InvalidCastException:无法将对象从DBNull强制转换为其他类型,c#,oracle,C#,Oracle,我的代码中有一个异常。我已经尝试将int64更改为int32,但这并没有改变它 在数据库中,表示“column_ID”的单元格具有数据类型编号 此代码中的第7行存在问题: private void dataGridView_ArticleINVIA_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex >= 0 && e.RowIndex <= (sender

我的代码中有一个异常。我已经尝试将int64更改为int32,但这并没有改变它

在数据库中,表示“column_ID”的单元格具有数据类型编号

此代码中的第7行存在问题:

private void dataGridView_ArticleINVIA_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex >= 0 && e.RowIndex <= (sender as DataGridView).Rows.Count - 1)
    {
        try
        {
            Int64 id_riga = Convert.ToInt64((sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value);
            //Exception thrown here:
            int id_macchina = Convert.ToInt32((sender as 
                DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value);
            FormRecipeNote PopUpNote = new FormRecipeNote(id_macchina, 
                "MODIFICA", id_riga, 0);
            PopUpNote.ShowDialog(this);
            PopUpNote.Dispose();
         }
         catch (Exception Exc)
         {
             FormMain.loggerSoftwareClient.Trace(this.Name + " " + Exc);
         }
         //DataGrid_ArticleINVIA();
    }
}

有人能帮我解决这个问题吗?

您可以将有问题的行更改为:

int id_macchina = ((sender as DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value as int?).GetValueOrDefault();
如果列
column\u machina
的值在数据库中为空(在C中为
DBNull
),则这将为变量
id\u macchina
提供int(0)的默认值

试试这个:

object aa = DBNull.Value;
int a = (aa as int?).GetValueOrDefault();
它会成功的!如果列为
DBNull
,则该值将为0

*编辑*


但是尝试使用其他方法,这可能会隐藏一些错误,例如更改数据类型,如果类型很长且在数据库中不是int,则始终会将0分配给变量,这在过去发生在我身上,这要感谢@hvd在他的注释中指出了这一点。

正如错误消息所说,单元格的值为
DBNull.value
,它无法从该值转换为您想要的值(在本例中为
long
int
)。在转换/转换数字之前,您需要检查
DBNull

Int64 id_riga = 0;
object value = (sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value;
if(value != DBNull.Value) 
    id_riga = Convert.ToInt64(value);
因为这会增加一些恼人的开销,如果你做了这么多,你可能会想要一个帮助器方法来为你做这件事

public static long? getLongFromDB(object value)
{
    if (value == DBNull.Value) return null;
    return Convert.ToInt64(value);
}
那么您的代码可以是:

Int64 id_riga = getLongFromDB((sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value)
    .GetValueOrDefault();

你的一些评论让我有点困惑。例如,在您的代码中,注释表明包含
ToInt32
的行是发生错误的地方,但错误消息清楚地显示错误是从
ToInt64
中抛出的

另外,您说过数据库中的值不是null。如果这是真的,那么就不会得到DBNull值,因此可能值得对代码进行一点扩展,以便在转换之前可以放置一些断点并直接检查单元格中的值

我在下面发布了一些您可以使用的示例代码,包括一个您可能会觉得有用的转换助手函数

//--------- inside the try block of your event handler -----------//
        var row = (sender as DataGridView).Rows[e.RowIndex];
        object objId = row.Cells["column_ID"].Value;
        object objMachine = row.Cells["column_Machine"].Value;
        // place a breakpoint on the line below, 
                    // so you can inspect the "obj..." values above to see
                    // if they are DBNull or not.

        var id_riga = objId.FromDb<Int64>();
        var id_macchina = objMachine.FromDb<Int32>();
//-----------continue your code here---------//

//----outside the form class, possibly in a separate file -----/
static class DbObjectExtensions {
    public static T FromDb<T>(this object dbObj, T defaultValueIfNull = default(T)) where T : IConvertible {
        if (Convert.IsDBNull(dbObj))
            return defaultValueIfNull;
        if (dbObj is T)
            return (T)dbObj;
        return (T)Convert.ChangeType(dbObj, typeof(T));
    }
}

根据您自己的个人偏好,上述范例可能比其他答案中描述的可空版本更容易理解。

例外情况是告诉您确切需要知道的内容-
行[e.RowIndex]。单元格[“column\u Machine”]。Value
DbNull
,并且不能将
DbNull
强制转换为任何其他类型。在调用
Convert.ToInt32
之前,检查您的
column\u机器
单元格是否为
DbNull
。您的意思是我只需要检查值是否为DbNull?如果是这样的话?我在数据库中检查了该值,但没有NULL@Laxedur正确,它不是
null
,而是
DBNull
。这两个是不同的。根据经验,如果你可以对一个对象调用Dispose,你应该用一个using块围绕它:
using(FormRecipeNote PopUpNote=new-FormRecipeNote(id_macchina,“MODIFICA”,id_riga,0)){PopUpNote.ShowDialog(this);}
它不是一个可为null的
int
,它使用的是
DBNull
而不是
null
。但这将解决问题:)您正在描述问题的原因,我正在解决问题!!为什么不投票@实际上,从技术上讲,它会起作用的。由于
DBNull
不是
int
int?
类型,转换失败,而
as
的结果是,当成功转换实际的
int
时,它返回
null
。然而,它非常令人困惑,因为它给人一种错误的印象,认为它不起作用,而且不清楚它到底在做什么,所以可读性受到很大影响。@MSakherSawan你是对的,它会起作用。但我同意Servy的观点,这很令人困惑。此外,它还可能隐藏一个bug:如果该值实际上是其他类型的,那么您需要一个响亮的错误,而不是静静地返回
null
。一旦它成为一个常见的习惯用法,它就不再令人困惑。我已经看到了足够多的使用,不会被它搞糊涂,所以+1来自我。将不同类型(例如服务器类型更改,您现在得到一个
long
)作为
null
进行静默处理是一个有效的观点,但是@MSakherSawan的数量可以忽略不计。此外,您断言它将不起作用(即使它会起作用)。@Servy感谢您的回复,明天我将看看是否可以使用您的代码来解决此问题
//--------- inside the try block of your event handler -----------//
        var row = (sender as DataGridView).Rows[e.RowIndex];
        object objId = row.Cells["column_ID"].Value;
        object objMachine = row.Cells["column_Machine"].Value;
        // place a breakpoint on the line below, 
                    // so you can inspect the "obj..." values above to see
                    // if they are DBNull or not.

        var id_riga = objId.FromDb<Int64>();
        var id_macchina = objMachine.FromDb<Int32>();
//-----------continue your code here---------//

//----outside the form class, possibly in a separate file -----/
static class DbObjectExtensions {
    public static T FromDb<T>(this object dbObj, T defaultValueIfNull = default(T)) where T : IConvertible {
        if (Convert.IsDBNull(dbObj))
            return defaultValueIfNull;
        if (dbObj is T)
            return (T)dbObj;
        return (T)Convert.ChangeType(dbObj, typeof(T));
    }
}
//assuming -1 isn't a valid 
var id_riga = objId.FromDb<Int64>(-1); id
if (id_riga == -1) { /*handle case for null db value*/ }