c# + oracle 中处理 null 必须显式识别 dbnull.value,不可用 null 判断或直接类型转换;应使用 isdbnull() 检查后取值,避免 nullreferenceexception。
直接用 datarow["xxx"] 取值,遇到数据库字段为 null 就崩,这是 c# + oracle 最典型的 nullreferenceexception 场景——不是代码写错了,是没处理好 oracle 的空值语义。
Oracle NULL 和 .NET null 的映射关系不一致
Oracle 的 NULL 在 OracleDataReader 或 DataTable 中不会自动转成 C# 的 null,而是返回 DBNull.Value。直接调用 .ToString()、(int)xxx 或访问属性就会炸。
-
DataRow["name"] == null永远为false,哪怕数据库里是 NULL;得用DataRow["name"] == DBNull.Value判断 -
OracleDataReader.GetValue(i)返回的是object,对数字/日期字段,它可能是DBNull.Value,也可能是真实值,不能无脑强转 - 用
Convert.IsDBNull()比手动比对DBNull.Value更安全(尤其在多数据提供者场景下)
DataReader 读取时避免 NullReference 的写法
别碰 reader["col"] 这种索引器,它底层会做类型转换,出错不报具体列名。优先用带类型检查的 GetXXX 方法。
- 用
reader.IsDBNull(i)先判断第i列是否为空,再调用reader.GetString(i)、reader.GetInt32(i)等 - 如果列名已知,用
reader.GetOrdinal("col_name")缓存序号,避免每次查列名开销 - 对可空类型,直接写
reader.IsDBNull(i) ? null : (int?)reader.GetInt32(i),别用as int?——GetInt32本身就不接受DBNull,必须先判空
DataTable 场景下安全取值的惯用模式
DataTable 看似简单,但 DataRow["col"] 返回 object,且默认 AllowDBNull = true,空值陷阱更隐蔽。
- 永远不用
row["col"].ToString()—— 改成row["col"] == DBNull.Value ? string.Empty : row["col"].ToString() - 对数值列,用
Convert.ToInt32(row["col"])是危险的,它内部会把DBNull当 0 处理,掩盖问题;应显式判空后构造可空类型 - 批量处理时,提前用
dt.Columns["col"].DataType检查列类型,避免对字符串列误用DateTime.Parse
最麻烦的不是写判空逻辑,而是团队里有人偷偷用 ?.ToString() 或 ?? "" 去“快速修复”,结果把 DBNull 当成 null 隐蔽传递下去——Oracle 的空值必须显式识别,绕不开这一层。











