Is it possible to continue running code from the point of failure?

▼魔方 西西 提交于 2019-12-11 05:00:24

问题


Okay, I have some very simple code which I will post below. Essentially, I have a connection to a database and I want to map a subset of columns in a query to a particular class. The problem is that it is possible for these to be null.

I would like to know if it is possible if an exception is thrown at a particular line, can we resume the entire block from the next line.

So if this code below was to execute and Line 6 catches an error. Is there an elegant way to catch the exception and make the code resume running at line 7. Essentially making it as though line 6 was never executed.

 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;
    }

It is important to note I am not asking for best practice, it is not something I intend to use in actual code (unless its absolutely genius). I simply want to know if this is possible and how one would go about doing this if it were.

My Research

Most of my research is proactive as opposed to reactive. I would attempt to know if it is possible for the given field to be null before it is read from. If it is, then I'd do a check to determine if the field is null and then set it to a default value. It essentially avoids the possibility of an error happening which I believe is a very good solution. I just wanted to attempt this as I know that when an exception is thrown, the most inner exception contains the line number at which it was thrown. Based on this if you put the exception inside of the class throwing the exception you should hypothetically be able to use reflection in order to continue running from its last point. I'm just not sure how you'd go about doing this. I've also considered the possibly of putting try catches around every single line which I think would be very effective; however, I think that it would be very ugly.


回答1:


No, what you are asking for is not possible in C#.

Instead the proper solution to this problem is to use better parsing methods that won't throw exceptions in the first place. If your input values can be null, then use parsing methods that can accept null values.

The first thing you probably need to do is use nullable types for your int/bool fields, so that you can support null values. Next, you'll need to create your own methods for parsing your ints/bools. If your input is null, return null, if not, use int.TryParse, bool.TryParse (or as for each if your input is the proper type, just cast to object).

Then by using those methods, instead of Convert, you won't be throwing exceptions in the first place (which you shouldn't be doing here even if it could work, because exceptions are for exceptional cases, not expected control flow).




回答2:


If the exception is expected then it is not exceptional. Never never never catch a null reference exception. A null reference exception is a bug. Instead, write code to avoid the bug.

You can easily write helper methods that test for null, or use methods like Int32.TryParse that can handle malformed strings.




回答3:


Check for IsDBNull

SqlDataReader.IsDBNull Method

And Reader has methods for each SQL datatype
For example

SqlDataReader.GetSqlBoolean

If the data is in SQL as string (char,nchar) then first check for null and then TryParse
For example

DateTime.TryParse

And ordinal position is faster
This is a sample for a nullable Int16

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

If you want a default

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



回答4:


You'd need a try/catch around every single variable assignment, and you'd need to initialize all your Column instance values before you tried. This would be relatively slow.

As for reflection based on the line number: I wouldn't rely on the line number because one simple, innocent change to the code will throw it off completely.

I'd check for nulls specifically. If you expect them you can't hardly call them "exceptions". The method that does that is reader.IsDBNull. It takes the column index (not the column name) so you'll need to resolve the index using reader.GetOrdinal:

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


来源:https://stackoverflow.com/questions/18595060/is-it-possible-to-continue-running-code-from-the-point-of-failure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!