4

我正在查看我正在开发的 .net 程序的一些代码。该程序的前任作者在一年前将代码提供给了我。突然,我看到一个我没有接触过的代码抛出的异常:

if ((string)row["LevelName"] != "ABC")

例外是“无法将 'System.DBNull' 类型的对象转换为 'System.String' 类型。

我认为该字符串是可以为空的数据类型,那么我怎么可能得到这个异常呢?

4

5 回答 5

9

我相信您正在寻找的是:

if ((row["LevelName"] as String) != "ABC")

DBNull 和 String 之间没有隐式转换。

它以前可能有效,因为恰好在您的数据库中的该列中没有空值。也许某些数据已损坏,或者有人更改了表上的 NOT NULL 约束。

基本上,如果你显式地强制转换某些东西,你最好确保它们具有兼容的动态类型,否则会引发异常。运算符基本上说“如果可能,将as其转换为 this,否则逻辑值为 null。” 显然,as运算符仅适用于引用类型,因为结构不能为空。

于 2011-11-07T23:05:51.480 回答
7

DBNull是它自己的类,它在一个名为Value的属性中包含其自身的单例实例。DBNull.Value 不等于 null,因为它是对此类实例的引用。

大多数(如果不是所有)数据库包装器都将返回DBNull.Value,而不是null在没有值时返回。造成这种情况的原因之一是因为返回一个实数null可能意味着根本没有行,而不仅仅是列中的空值(这取决于您用来获取值的对象)。

通常,as运算符对任何可为空的类型(包括 )都非常有用,DBNull并且可以与它们一起使用string

string str = reader["Name"] as string;
int? i = reader["Age"] as int?;

可能还值得一提的是?? 运算符在这里也非常有用,当您需要一个不可为空的值类型时(尽管它看起来不太漂亮)。

int i = reader["Age"] as int? ?? -1;

作为 LINQ 选择子句中的一个以防万一的场景,我发现这非常方便。

于 2011-11-07T23:08:34.780 回答
4

DBNull 表示给定的数据库列中没有数据。如果在数据库中创建了新记录但没有为“LevelName”列分配值,则可能会发生这种情况。

DBNull 与空对象引用或空字符串变量不同。DBNull 表示从未设置过列数据。如果将 null 分配给“LevelName”列,则该列已被初始化,它将返回 null(不是 DBNull)。

于 2011-11-07T23:11:41.480 回答
3

DBNull 表示数据库中的空值。这与 .NET null 不同,后者表示空引用。

代码突然失败,因为有人更改或插入了一条包含空值的记录。

是的,字符串可以为空,但是您将 dbnull 转换为字符串。您必须检查 dbnull,如果存在则将其替换为 null。

于 2011-11-07T23:10:58.303 回答
2

null.NET和.NET 之间存在差异DBNull.Value。在这里,您可以看到DBNull类是什么以及该类的Value字段。

你应该能够做这样的事情:

if (row["LevelName"].Value == DBNull.Value)
    return false;
else if (row["LevelName"].ToString() != "ABC")
    // do something
    // ....
于 2011-11-07T23:06:10.427 回答