Внутренние исключения C#

История: у меня есть 3 функции из 3 разных классов. Функции вызова порядка:

Form1_Load(...) -> Student.GetAllStudents(...) -> StudentDAL.GetStudentInformation(...) -> ConnectionManager.GetConnection(...)

Что я хочу сделать, это отобразить StackTrace самой внутренней функции, т.е.ConnectionManager.GetConnection(), в MessageBox в классе Form1. Другими словами, я не хочу использовать MessageBox в любых внутренних классах, но только во внешнем большинстве классов, которые являются классом Form1.

Проблема: чтобы получить внутренние исключения, мы можем использовать InnerException или же GetBaseException() и т. д., но когда я пытаюсь получить внутреннее исключение, оно выдает исключение "Ссылка на объект не установлена ​​для экземпляра", что означает, что нет внутреннего исключения, и, когда я проверяю, значение также null, Все, что я хочу знать здесь, почему это null? Разве это не должно содержать ссылку на внутреннее исключение? Поправьте меня если я ошибаюсь.

Функциональные коды:

  1. 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")));
               }
    
  2. GetAllStudents(...)

    public SqlDataReader GetAllStudents()
          {
               try
               {
                    return StudentInformationDataAccessLayer.GetStudentInformation();
               }
               catch (Exception ex)
               {
                    throw ex;
               }
          }
    
  3. 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;
               }
          }
    
  4. 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;          
 }

Но, пожалуйста, помните две вещи:

  1. Не печатать throw ex, просто throw,

  2. Делайте это только в том случае, если вы действительно хотите что-то сделать с этим исключением перед тем, как выбросить. Если у вас нет такого плана, просто не поймите его на этом уровне.

Я хотел бы сделать что-то вроде:

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);
Другие вопросы по тегам