Подтвердить что ты не робот

VB.NET Попробуйте Catch с несколькими блоками Catch

Это действительно странная проблема. У нас есть Try Catch с несколькими блоками Catch. Первый блок Catch не имеет кода, просто комментарий.

Try
  'Some Code
Catch ex As ThreadAbortException
  'Do Nothing
Catch ex As Exception
  HandleException(ex)
End Try

Если генерируется исключение, отличное от исключения ThreadAbortException, оно ловутся вторым Catch, как и ожидалось. Однако при переходе по коду в VS2010 ex-объект в этом случае ничего. До сих пор мы нашли два способа "исправить" эту проблему.

Исправить 1: Переименуйте первую переменную исключения.

Try
  'Some Code
Catch tex As ThreadAbortException
  'Do Nothing
Catch ex As Exception
  HandleException(ex)
End Try

Исправить 2: Добавить строку кода в первый блок Catch.

Try
  'Some Code
Catch ex As ThreadAbortException
  Dim i As Integer = 1
Catch ex As Exception
  HandleException(ex)
End Try

Код в HandleException, похоже, все еще функционирует должным образом, если он запускается, в любом из перечисленных случаев. Это ошибка в Visual Studio или отладчике? Или мы что-то упустили, и первый блок кода выше недействителен?

Все это делается в .NET 4.0.

4b9b3361

Ответ 1

Teejay имеет правильный ответ.

Однако, если ваш блок Catch пуст, нет смысла обрабатывать это исключение. Вы просто хотите, чтобы последний блок не мог его поймать. Вы можете использовать свой метод, но считайте, что наличие пустого блока Catch обычно неприемлемо: исключения не должны быть пойманы или должны быть обработаны должным образом; проглатывание их молчаливо должно рассматриваться как ошибка. Ваш случай является исключением из этого правила, но, как таковой, он должен быть документирован в коде, поскольку он будет путать осторожных сторонников в противном случае.

Ну, у VB есть особая идиома для такой ситуации:

Try
    ' …
Catch ex As Exception When Not TypeOf ex Is ThreadAbortException
    ' Only executed if `ex` isn’t a ThreadAbortException
End Try

Этот код вообще не улавливает ThreadAbortException, что правильно делать, если вы не хотите его обрабатывать: ThreadAbortException не может проглатываться, поэтому даже когда вы его поймаете, он будет быть сброшенным в конце блока Catch.

Обратите внимание, что это принципиально отличается от ответа SysDragons, который использует обычный оператор If, в то время как код здесь использует специальное предложение в инструкции Catch в качестве фильтра.

Ответ 2

Кажется, это ошибка отладчика VS.

Доказательство

Если вы пишете:

Try
    Throw New InvalidOperationException("MESSAGE")
Catch ex As ArgumentException
    'Do Nothing
Catch ex As Exception
    Debug.WriteLine(ex)
End Try

и вы смотрите ex, он оценивает Nothing в режиме Quickwatch

НО

в консоли программа корректно печатает System.InvalidOperationException: MESSAGE

Ответ 3

Хорошо, дайте мне понять...

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

Try
   'Some Code
Catch ex As ThreadAbortException
   'Do something(ex: HandleExceptionSub())
Catch ex As Exception
   HandleException(ex)
End Try

Если вы "поймаете" исключение, вам нужно что-то сделать с ним.

EDIT:

Я также нашел эту информацию, которая поможет вам сообщить вам о том, как работает попытка catch:

Несколько блоков Catch

Блок try может выдавать несколько исключений, которые могут обрабатываться с помощью нескольких блоков catch. Помните, что более специализированный блок catch должен быть до обобщенного. В противном случае компилятор покажет ошибку компиляции. Несколько блоков уловов

Это не ошибка с Debugger. Отладчик призван помочь вам найти и обработать все исключения.

EDIT: Кажется, что это исключение можно полностью исключить из того, что я прочитал в другом посте. И кажется, что лучше избегать исключения вместо того, чтобы не иметь дело с ним. Обработка ThreadAbortException

EDIT: Просто попробовал больше информации о нескольких блоках catch. Это из MSDN и заявляет, что блоки блокировки после того, как пустой блок catch никогда не будет достигнут... Попробуйте окончательное утверждение Catch Дальнейшее доказательство того, что это НЕ ошибка, но ожидаемая функциональность обеспечивает выполнение всех исключений в вашем коде.

EDIT: Чтобы установить некоторых людей в комментариях прямо, я создал очень простую тестовую программу, чтобы убедиться, что это действительно ошибка. Мои выводы заключаются в том, что блоки захвата работают отлично. Кажется, что после документированного способа MSDN создания Try Catch с несколькими блоками Catch работает, как говорится.

    private void button1_Click(object sender, EventArgs e)
    {
        try
        {
            if (textBox1.Text == "")
            {
                throw new ArgumentNullException("textBox1", "TextBox can not be empty");
            }
            else
            {
                MyString(textBox1.Text);
            }
        }
        catch (ArgumentNullException ex)
        {
            //nothing
        }
        catch (Exception ex)
        {
            MessageBox.Show("Test: " + ex.Message);
        }
    }

    private int MyString(string text)
    {
        return int.Parse(text);
    }

Я создал простую форму с помощью кнопки и текстового поля. Если текстовое поле пуст, я выкидываю ArgumentNullException, а в "MyString" я разбираю строку в целое число, которое выдает "FormatException". Наличие пустого блока catch, который НЕ является правильным способом обработки "пойманного" исключения, действительно работает. Так что, насколько я вижу, это не ошибка. Очевидно, единственное, с чем я могу согласиться с Teejay и Konrad, это то, что вы не можете поймать и обработать исключение ThreadAbortException с помощью метода try catch. Решение Konrad - лучший способ закодировать ваш улов try.