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

时间:2012-12-27 17:34:24

标签: c# oracle

我的代码中有一个例外。我已经尝试将我的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)

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

3 个答案:

答案 0 :(得分:8)

正如错误消息所示,单元格的值为DBNull.Value,并且无法将其转换为您想要的值(在这种情况下为long或{{1 }})。在转换/转换数字之前,您需要检查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);
}

答案 1 :(得分:3)

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

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

如果数据库中列id_macchina的值为null(在C#中为column_Machine),则会将int(0)的默认值赋予变量DBNull < / p>

试试这个:

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

它会起作用!如果列为DBNull,则值为0。

*编辑*

但是尝试使用别的东西,这可能会隐藏一些错误,例如更改数据类型,如果类型很长而不是数据库中的int,将始终为变量赋值0,它在过去发生在我身上,感谢@hvd在他的评论中表明了这一点。

答案 2 :(得分:1)

我对你的一些评论感到有些困惑。例如,在您的代码中,注释指示包含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));
    }
}

我还想澄清一个我在上面看到的评论说“......它不是空的,它是DBNull。两者是不同的”。这个陈述在C#中是正确的,但它在写入的上下文中实际上是误导性的。它的编写是为了回应之前的评论,即“[I]检查数据库的值并且不是NULL”。为了澄清,在大多数.Net数据库提供程序中,DBNull表示数据库字段中的NULL。所以实际上,数据库中的NULL值通常与C#中的DBNull相同。因此,如果OP在说数据库值为NOT 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版本更容易理解。