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

本文关键字:开始 继续 运行 代码 故障 是否 | 更新日期: 2023-09-27 18:29:58

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

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

因此,如果执行下面的代码,并且第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。如果是,那么我会进行检查以确定字段是否为null,然后将其设置为默认值。它基本上避免了发生错误的可能性,我认为这是一个非常好的解决方案。我只是想尝试一下,因为我知道当抛出异常时,最内部的异常包含抛出它的行号。基于此,如果您将异常放入引发异常的类中,则假设您应该能够使用反射,以便从其最后一点开始继续运行。我只是不确定你会怎么做。我还考虑过在每一条线上进行尝试接球的可能性,我认为这会非常有效;然而,我认为这将是非常丑陋的。

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

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

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

您可能需要做的第一件事是为int/bool字段使用可为null的类型,这样您就可以支持null值。接下来,您需要创建自己的方法来解析int/boll。如果您的输入为null,则返回null;如果不是,则使用int.TryParsebool.TryParse(如果输入的类型正确,则分别使用as,仅强制转换为object)。

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

如果异常是预期的,则它不是异常从不捕获空引用异常空引用异常是一个错误。相反,编写代码以避免该错误。

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

检查IsDBNull

SqlDataReader.IsDBNull方法

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

SqlDataReader.GetSqlBoolean

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

DateTime.TryParse

顺序位置更快
这是可为null的Int16 的示例

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

如果你想要一个默认的

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

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

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

我会专门检查null。如果你期待它们,你几乎不能称它们为"例外"。这样做的方法是reader.IsDBNull。它采用列索引(而不是列名),因此您需要使用reader.GetOrdinal:解析索引

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