C# System.InvalidCastException:无法将对象从 DBNull 强制转换为其他类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14058745/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
System.InvalidCastException: Object cannot be cast from DBNull to other types
提问by Laxedur
I have an exception in my code. I have already tried to change my int64 to int32 but that doesn't change it.
我的代码中有一个例外。我已经尝试将我的 int64 更改为 int32 但这并没有改变它。
In the database, the cells that represent "column_ID" have datatype NUMBER.
在数据库中,代表“column_ID”的单元格的数据类型为 NUMBER。
The problem is at line 7 in this code:
问题出在这段代码的第 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();
}
}
the error is:
错误是:
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)
Can someone help me resolve this?
有人可以帮我解决这个问题吗?
回答by Sawan
You can change the problematic line to :
您可以将有问题的行更改为:
int id_macchina = ((sender as DataGridView).Rows[e.RowIndex].Cells["column_Machine"].Value as int?).GetValueOrDefault();
This will give the default value of int (0) to the variable id_macchina
if the value of the column column_Machine
is null in the database (will be DBNull
in C#)
id_macchina
如果column_Machine
数据库中列的值为空(将DBNull
在 C# 中),这将为变量提供默认值 int (0 )
Try this:
尝试这个:
object aa = DBNull.Value;
int a = (aa as int?).GetValueOrDefault();
It will work! the value will be 0 if the column is DBNull
.
它会起作用!如果列是 ,则该值将为 0 DBNull
。
* EDIT *
* 编辑 *
But try to use something else, this may hide some bugs, such as changing the data type, if the type is long and not int in the database, will always assign 0 to the variable, it happened with me in the past, thanks to @hvd to to indicate to that in his comment.
但是尝试使用别的东西,这可能会隐藏一些bug,比如改变数据类型,如果类型是long而不是数据库中的int,将始终为变量赋值0,过去发生在我身上,感谢@hvd 在他的评论中指出这一点。
回答by Servy
As the error message says, the value of the cell is DBNull.Value
and it can't convert from that to whatever you want it to be (in this case a long
or an int
). You need to check for DBNull
before converting/casting the number:
正如错误消息所说,单元格的值是DBNull.Value
,并且无法从该值转换为您想要的任何值(在本例中为 along
或 an 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);
Because this adds some annoying overhead, if you do this much you'll probably want to make a helper method that does it for you.
因为这会增加一些烦人的开销,如果你做了这么多,你可能想要制作一个帮助方法来为你做这件事。
public static long? getLongFromDB(object value)
{
if (value == DBNull.Value) return null;
return Convert.ToInt64(value);
}
Then your code can be:
那么你的代码可以是:
Int64 id_riga = getLongFromDB((sender as DataGridView).Rows[e.RowIndex].Cells["column_ID"].Value)
.GetValueOrDefault();
回答by drwatsoncode
I'm a bit confused by some of your comments. Like for example, in your code the comment indicates that the line containing ToInt32
is where the error occurs, but the error message clearly shows that the error is thrown from within ToInt64
.
我对你的一些评论感到有些困惑。例如,在您的代码中,注释表明包含的行ToInt32
是发生错误的地方,但错误消息清楚地表明错误是从ToInt64
.
Also, you said that the value in the database is NOT null. If that is true, you would not get the DBNull value, so it may be worthwhile to expand your code a bit so that you can so you can place some breakpoints and inspect the values in the cells directly before trying to convert them.
另外,您说数据库中的值不为空。如果这是真的,您将不会获得 DBNull 值,因此可能值得稍微扩展您的代码,以便您可以放置一些断点并在尝试转换之前直接检查单元格中的值。
I've posted some example code below that you can use, including a conversion helper function that you might find useful.
我在下面发布了一些您可以使用的示例代码,其中包括一个您可能会觉得有用的转换辅助函数。
//--------- 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));
}
}
I also want to clear up a comment I saw above that said "...it's not null, it's DBNull. The two are different". That statement is true in general, in C#, however it's actually misleading in the context it was written. It was written in response to the previous comment that said "[I] checked on database the value and is not NULL". For clarification, a NULL in a database field IS represented by DBNull in most .Net database providers. So in fact, a NULL value in the database IS usually the same as DBNull in C#. So if the OP is correct in saying that the database value is NOT NULL, then it doesfollow that the cell value should not be DBNull.
我还想澄清我在上面看到的一条评论,即“......它不是空的,它是 DBNull。两者是不同的”。这句话在 C# 中通常是正确的,但实际上它在编写的上下文中具有误导性。它是为了回应先前的评论而写的,该评论说“[I] 在数据库上检查了值并且不是 NULL”。为了澄清起见,在大多数 .Net 数据库提供程序中,数据库字段中的 NULL 由 DBNull 表示。所以实际上,数据库中的 NULL 值通常与 C# 中的 DBNull 相同。因此,如果 OP 正确地说数据库值不是 NULL,那么它确实遵循单元格值不应该是 DBNull。
Of course it is still true that null
is not the same as DBNull
, so checking to see if an object is null does not determine whether it is DBNull or not, (but that is not what the OP said).
当然,这null
与 不一样仍然是正确的DBNull
,因此检查对象是否为 null 并不能确定它是否为 DBNull,(但这不是 OP 所说的)。
As a final note, the extension method I wrote, FromDB
, includes an optional parameter for a default return value in the case that the object passed is DBNull.
This can be used as follows:
最后要说明的是,我编写的扩展方法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*/ }
Depending on your own personal preferences the above paradigm might be easier to understand than the Nullable version described in other answers.
根据您自己的个人喜好,上述范例可能比其他答案中描述的 Nullable 版本更容易理解。