系统.InvalidCastException:对象不能从DBNull转换为其他类型

本文关键字:转换 其他 类型 DBNull InvalidCastException 对象 不能 系统 | 更新日期: 2023-09-27 17:49:36

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

在数据库中,表示"column_ID"的单元格的数据类型为NUMBER。

问题在代码第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();
    }
}

错误是:

System.InvalidCastException: Object cannot be cast from DBNull to other types.
   at System.DBNull.System.IConvertible.ToInt64(IFormatProvider provider)
   at System.Convert.ToInt64(Object value)
   at Software_Client.FormSendReceiveRecipe.dataGridView_ArticleINVIA_CellDoubleClick(Object sender, DataGridViewCellEventArgs e)

谁能帮我解决这个问题?

系统.InvalidCastException:对象不能从DBNull转换为其他类型

正如错误消息所说,单元格的值是DBNull.Value,它不能从该值转换为您想要的任何值(在这种情况下是longint)。您需要在转换/转换数字之前检查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();

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

int id_macchina = ((sender as DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value as int?).GetValueOrDefault();

如果列column_Machine的值在数据库中为空(c#中为DBNull),则将int(0)的默认值赋给变量id_macchina

试试这个:

object aa = DBNull.Value;
int a = (aa as int?).GetValueOrDefault();

会成功的!如果列为DBNull,则该值为0。

* EDIT *

但是尝试使用其他东西,这可能会隐藏一些bug,例如改变数据类型,如果类型是长而不是数据库中的int,将始终将0分配给变量,这发生在我过去,感谢@hvd在他的评论中指出。

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

另外,您说数据库中的值不是空的。如果这是真的,您将无法获得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));
    }
}

我还想澄清我在上面看到的一个评论,说"……它不是null,而是DBNull。这两者是不同的。"这句话在c#中通常是正确的,但实际上在它所写的上下文中是误导的。这是为了回应之前的评论,说"[我]检查数据库的值,不是NULL"。澄清一下,在大多数。net数据库提供程序中,数据库字段中的NULL由DBNull表示。所以实际上,数据库中的NULL值通常与c#中的DBNull值相同。因此,如果OP说数据库值不是NULL是正确的,那么就意味着单元格值不应该是DBNull。

当然,nullDBNull是不一样的,所以检查一个对象是否为null并不能确定它是否为DBNull(但OP不是这么说的)。

最后需要说明的是,我编写的扩展方法FromDB包含一个可选参数,用于传递的对象是DBNull时的默认返回值。可以这样使用:

//assuming -1 isn't a valid 
var id_riga = objId.FromDb<Int64>(-1); id
if (id_riga == -1) { /*handle case for null db value*/ }

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