Внутренние исключения C#
История: у меня есть 3 функции из 3 разных классов. Функции вызова порядка:
Form1_Load(...)
-> Student.GetAllStudents(...)
-> StudentDAL.GetStudentInformation(...)
-> ConnectionManager.GetConnection(...)
Что я хочу сделать, это отобразить StackTrace самой внутренней функции, т.е.ConnectionManager.GetConnection()
, в MessageBox
в классе Form1. Другими словами, я не хочу использовать MessageBox
в любых внутренних классах, но только во внешнем большинстве классов, которые являются классом Form1.
Проблема: чтобы получить внутренние исключения, мы можем использовать InnerException
или же GetBaseException()
и т. д., но когда я пытаюсь получить внутреннее исключение, оно выдает исключение "Ссылка на объект не установлена для экземпляра", что означает, что нет внутреннего исключения, и, когда я проверяю, значение также null
, Все, что я хочу знать здесь, почему это null
? Разве это не должно содержать ссылку на внутреннее исключение? Поправьте меня если я ошибаюсь.
Функциональные коды:
Form1_Load(...)
private void Form1_Load(object sender, EventArgs e) { try { DataTable dt = new DataTable(); dt.Load((**new Student().GetAllStudents()**)); if (dt.Rows.Count <= 0) { MessageBox.Show("Student table empty."); } else { this.dataGridView1.DataSource = dt; } } catch (Exception ex) { MessageBox.Show(ex.Message+Environment.NewLine+"Source(s) : "+ex.StackTrace.Substring(0, ex.StackTrace.LastIndexOf("at"))); }
GetAllStudents(...)
public SqlDataReader GetAllStudents() { try { return StudentInformationDataAccessLayer.GetStudentInformation(); } catch (Exception ex) { throw ex; } }
GetStudentInformation(...)
public static SqlDataReader GetStudentInformation() { try { SqlConnection sqlCon = null; sqlCon = ConnectionManager.GetConnection(); if (sqlCon == null) { return null; } String Query = null; Query = "SELECT * FROM [dbo].[Student]"; SqlCommand cmd = new SqlCommand(Query, sqlCon); SqlDataReader dr = null; dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); return dr; } catch (Exception ex) { throw ex; } }
GetConnection(...)
public static SqlConnection GetConnection() { String _connectionString = null; _connectionString = ConfigurationManager.ConnectionStrings["Default"].ConnectionString; if (_connectionString == null) { return null; } try { SqlConnection connection = new SqlConnection(_connectionString); connection.Open(); return connection; } catch (Exception ex) { throw ex; } }
4 ответа
Если вы хотите перезапустить с внутренним набором исключений, используйте приведенный ниже код, но помните, что вы потеряете трассировку стека:
try
{
...
}
catch (Exception ex)
{
throw new Exception("message", ex);
}
Чтобы просто перебросить исключение и сохранить трассировку стека, используйте:
try
{
...
}
catch (Exception ex)
{
throw;
}
Если вы хотите, чтобы информация о трассировке стека и информации об исключениях сохранялась, вы должны изменить код, который перебрасывает перехваченные исключения, например:
}
catch(Exception ex)
{
// do what you need to do with ex
// ..
// rethrow..
throw; // notice this is not "throw ex";
}
Повторное выбрасывание исключения, используя только throw;
сохраняет исходную трассировку стека. Не обязательно будет внутреннее исключение, но это не то, о чем вы должны заботиться. То, что вам нужно знать, это трассировка стека, где возникла исключительная ситуация.
Не каждое исключение действительно имеет внутреннее исключение. Сначала проверьте, является ли внутренний ex null
и если это не так, обработайте его.
Сказав это, вы, конечно, можете повторно выдать свое исключение, как показано ниже:
catch(Exception ex)
{
// so smth
// ..
// rethrow..
throw;
}
Но, пожалуйста, помните две вещи:
Не печатать
throw ex
, простоthrow
,Делайте это только в том случае, если вы действительно хотите что-то сделать с этим исключением перед тем, как выбросить. Если у вас нет такого плана, просто не поймите его на этом уровне.
Я хотел бы сделать что-то вроде:
try
{
...
}
catch (Exception ex)
{
if (ex.InnerException == null)
throw ex;
else
throw ex.InnerException;
}
затем в какой-то момент, когда вы хотите выполнить трассировку стека, выполните что-то вроде:
StackTrace trace = new StackTrace(System.Threading.Thread.CurrentThread, true);
StackFrame[] frames = trace.GetFrames();
string result = string.Empty;
foreach (StackFrame sf in frames)
{
string += sf.GetMethod().Name;
}
MessageBox(result);