1

好的,我有一些非常简单的代码,我将在下面发布。本质上,我有一个到数据库的连接,并且我想将查询中的列子集映射到特定类。问题是这些可能为空。

我想知道如果在特定行抛出异常是否有可能,我们可以从下一行恢复整个块。

因此,如果要执行下面的代码并且第 6 行捕获到错误。有没有一种优雅的方法来捕获异常并使代码在第 7 行恢复运行。本质上使它好像第 6 行从未执行过。

 private static Column MapTableToColumn(OracleDataReader reader){
        Column c = new Column();
        c.ColumnName = Convert.ToString(reader["COLUMN_NAME"]);
        c.DataType = Convert.ToString(reader["DATA_TYPE"]);
        c.DataLength = Convert.ToInt32(reader["DATA_LENGTH"]);
        c.DataPrecision  = Convert.ToInt32(reader["Data_Precision"]);//<---Line 6
        c.DataScale = Convert.ToInt32(reader["Data_scale"]);//<--- Line 7
        c.AllowDBNull = Convert.ToBoolean(reader["ALLOW_DB_NULL"]);
        c.IsReadOnly = Convert.ToBoolean(reader["IS_READ_ONLY"]);
        c.IsLong = Convert.ToBoolean(reader["IS_LONG"]);
        c.IsKey = Convert.ToBoolean(reader["IS_KEY"]);
        c.KeyType = Convert.ToString(reader["KEY_TYPE"]);
        c.IsUnique = Convert.ToBoolean(reader["IS_UNIQUE"]);
        c.Description = Convert.ToString(reader["DESCRIPTION"]);
        return c;
    }

重要的是要注意我不是在寻求最佳实践,我不打算在实际代码中使用它(除非它绝对是天才)。我只是想知道这是否可能,如果可能的话,人们将如何去做。

我的研究

我的大部分研究都是主动的,而不是被动的。我会尝试知道在读取给定字段之前是否有可能为空。如果是,那么我会检查该字段是否为空,然后将其设置为默认值。它基本上避免了发生错误的可能性,我认为这是一个非常好的解决方案。我只是想尝试一下,因为我知道当抛出异常时,最内部的异常包含抛出它的行号。基于此,如果您将异常放在引发异常的类中,则假设您应该能够使用反射以便从最后一点继续运行。我只是不确定你会怎么做。我' 我还考虑了在每一行周围放置 try catch 的可能性,我认为这会非常有效;但是,我认为这会很丑陋。

4

4 回答 4

8

不,您所要求的在 C# 中是不可能的。

相反,这个问题的正确解决方案是使用更好的解析方法,这些方法一开始就不会抛出异常。如果您的输入值可以为 null,则使用可以接受 null 值的解析方法。

您可能需要做的第一件事是为您的 int/bool 字段使用可空类型,以便您可以支持空值。接下来,您需要创建自己的方法来解析 ints/bools。如果您的输入为 null,则返回 null,如果不是,则使用int.TryParse, bool.TryParse(或者as,如果您的输入是正确的类型,则为每个输入,只需转换为object)。

然后通过使用这些方法,而不是Convert,您将不会首先抛出异常(即使它可以工作,您也不应该在这里这样做,因为异常是针对异常情况,而不是预期的控制流)。

于 2013-09-03T14:44:01.637 回答
7

如果异常是预期的,那么它不是异常的。永远永远永远不会捕获空引用异常。空引用异常是一个错误。相反,编写代码来避免错误。

您可以轻松编写测试 null 的辅助方法,或使用Int32.TryParse可以处理格式错误的字符串的方法。

于 2013-09-03T14:50:58.770 回答
3

检查 IsDBNull

SqlDataReader.IsDBNull 方法

Reader 对每种 SQL 数据类型都有方法,
例如

SqlDataReader.GetSqlBoolean

如果数据在 SQL 中作为字符串 (char,nchar) 则首先检查 null 然后 TryParse
例如

日期时间.TryParse

序数位置更快
这是可为空的 Int16 的示例

Int16? ID; 
ID = rdr.IsDBNull(4) ? (Int16?)null : rdr.GetInt16(4);

如果你想要一个默认值

Int16 ID; 
ID = rdr.IsDBNull(4) ? 0 : rdr.GetInt16(4);
于 2013-09-03T14:46:16.580 回答
1

您需要尝试/捕获每个变量分配,并且您需要Column在尝试之前初始化所有实例值。这将是相对缓慢的。

至于基于行号的反射:我不会依赖行号,因为对代码的一个简单、无辜的更改会完全抛弃它。

我会专门检查空值。如果您期望它们,您几乎不能称它们为“例外”。这样做的方法是reader.IsDBNull。它采用列索引(不是列名),因此您需要使用以下方法解析索引reader.GetOrdinal

if (reader.IsDBNull(reader.GetOrdinal("Data_Precision"))) {
  // It's null
} else {
  // It's not null
}
于 2013-09-03T14:48:47.923 回答