是否可以从故障点继续运行代码?

时间:2013-09-03 14:38:27

标签: c# .net database oracle exception-handling

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

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

因此,如果以下代码执行,第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;
    }

重要的是要注意我不是要求最佳实践,这不是我打算在实际代码中使用的东西(除非它绝对天才)。我只是想知道这是否可行以及如果有的话会怎么做。

我的研究

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

4 个答案:

答案 0 :(得分:8)

不,你在C#中无法提出要求。

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

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

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

答案 1 :(得分:7)

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

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

答案 2 :(得分:3)

检查IsDBNull

SqlDataReader.IsDBNull Method

Reader有针对每种SQL数据类型的方法 例如

SqlDataReader.GetSqlBoolean

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

DateTime.TryParse

顺序位置更快 这是可以为空的Int16

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

如果您想要默认

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

答案 3 :(得分:1)

您需要对每个变量赋值进行try / catch,并且在尝试之前需要初始化所有Column实例值。这会相对较慢。

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

我会特别检查空值。如果你期待它们,你就不能称之为“例外”。执行此操作的方法是reader.IsDBNull。它采用列索引(而不是列名),因此您需要使用reader.GetOrdinal来解析索引:

if (reader.IsDBNull(reader.GetOrdinal("Data_Precision"))) {
  // It's null
} else {
  // It's not null
}