C # - бесконечный цикл при исключении?

2

У меня есть следующий код:

protected void ExecuteInTransaction(Action action)
{
    using (SQLiteTransaction transaction = connection.BeginTransaction())
    {
        try
        {
            action.Invoke();
            transaction.Commit();
        }
        catch(Exception)
        {
            transaction.Rollback();
            throw;
        }
    }
}

При тестировании этого класса мне удалось исключить исключение, чтобы проверить ветвь catch.

Изображение 16924

Когда я работаю в режиме отладки, я продолжаю выполнение этого метания, чтобы посмотреть, как обрабатывается вызывающий класс, но исключение никогда не выбрасывает метод, вместо этого он, как исключение, постоянно бросается и поймается, бросается и пойманный снова и снова, никогда не выходя из функции.

В режиме Release приложение замерзает и перестает работать:

Изображение 16925

Кто-нибудь знает, почему это происходит, и как я могу избежать этого?

Заранее спасибо!

  • 0
    Перехватите специфическое для SQL исключение, распечатайте сообщение и заверните откат в попытку
Теги:
exception
exception-handling

4 ответа

2
Лучший ответ

Нет бесконечного цикла. Visual Studio просто останавливается в месте, где неперехваченное исключение прерывает программу. Попытка продолжить ничего не делает, потому что больше нечего выполнять (VS просто отображает одно и то же сообщение, чтобы напомнить вам об этом).

Если у вас есть обработчик try/catch в какой-либо вызывающей функции, вы сможете отлаживать там. (Но если этот обработчик перехвата снова заново, VS тоже остановится.)


Обратите внимание, что SQLiteTransaction автоматически обрабатывает откат при открытой транзакции; он разработан так, чтобы ваш код мог быть проще:

protected void ExecuteInTransaction(Action action)
{
    using (var transaction = connection.BeginTransaction())
    {
        action.Invoke();
        transaction.Commit();
    }
}
  • 0
    Ничего себе, не знал об этом поведении в SQLiteTransaction , SQLiteTransaction спасибо! Кажется, вы правы насчет неисследованного исключения, кажется, я думал, что поймал его с более высокого уровня, но на самом деле это не так. Спасибо вам всем!
1

Вы уверены, что catch стек, который может справиться с этой ошибкой? Диалог, который вы показали, - это то, что вы видите, когда Исключение выходит из верхней части Main метода программы. Сообщение отладчика на самом деле говорит вам, что оно было необработанным, поэтому на следующий шаг нет следующего утверждения.

0

Кто-нибудь знает, почему это происходит, и как я могу избежать этого?

Его трудно сказать, не видя ваш стек вызовов.

В общем, есть 3 возможных варианта:

  1. Исключение ломается выше стека.

  2. Там где-то в вашем стеке вызовов есть системный режим, и исключение проглатывается. Это происходит только при запуске 32-разрядного приложения на 64-битных окнах. Наиболее заметным примером является исключение, OnLoad() методом OnLoad() Form. См. VS2010 не показывает необработанное сообщение об исключении в приложении WinForms в 64-разрядной версии Windows для получения дополнительной информации.

  3. Исключение составляет поток ThreadPool и не распространяется на основной поток.

  • 0
    До меня дошло, что # 3 относится только к .NET версии 1.X. Но все еще возможно, что исключение перехватывается попыткой / перехватом в обратном вызове ожидания, который может не появиться в стеке вызовов.
-1

Возьмите throw; кода из блока catch. Если вы хотите знать, когда код переходит в блок catch, используйте Debug.WriteLine() останова или Debug.WriteLine().

Блок catch try/catch не захватывает исключений, брошенных в себе. Итак, throw; код создает необработанное исключение. Если вы хотите протестировать код, который в блоке catch добавьте throw; кода до конца блока try.

EDIT: Я не понимал, что OP хочет, чтобы исключение распространялось на цепочку. Он не упомянул об исключении, распространяющемся по цепочке, и его код не поддерживает поддержку исключения, которое распространяется, поскольку он не показывает код, который вызывает этот ExecuteInTransaction(Action). Блок catch может восстановить исключение, которое он ловит. Я согласен с этим. Однако код catch(Exception){ throw; } catch(Exception){ throw; } не будет повторно вводить один и тот же блок catch. Если бы это создало бы бесконечный цикл, и это не то, что происходит. Если есть блок try/catch, окружающий это, то внешний блок catch поймает повторное исключение, но его код включает только один блок catch. Поэтому, когда он пытается перестроить исключение, его не поймать, и приложение ломается.

Попробуйте что-то вроде этого:

private void Main()
{
    // Instantiate action variable. I know this wouldn't work, but it just for show.
    Action myAction;
    try
    {
        ExecuteInTransaction(myAction);
    }
    catch(Exception ex)
    {
        Debug.WriteLine("Error happened and transaction rolled back. " + ex.Message);
    }
}

protected void ExecuteInTransaction(Action action)
{
    using (SQLiteTransaction transaction = connection.BeginTransaction())
    {
        try
        {
            action.Invoke();
            transaction.Commit();
        }
        catch(Exception ex)
        {
            transaction.Rollback();
            throw ex;
        }
    }
}
  • 1
    Он не хочет проглотить исключение; это не заставило бы программу функционировать должным образом. Он хочет, чтобы транзакция откатилась, а затем исключение продолжало распространяться. Ваше утверждение, что блок catch не перехватывает исключение, которое он отбрасывает, неверно. это ловит это. Он сбрасывает его после выполнения чего-либо (в данном случае откат транзакции), но он действительно его ловит.
  • 0
    Именно поэтому я использую throw @Servy, я не мог бы объяснить это лучше
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню