Какой смысл вложенного блока try-catch? - PullRequest
3 голосов
/ 16 апреля 2011

Вот псевдокод:

try
{
  TextReader tr = new StreamReader("filename");
  try
  {
    string content = tr.ReadToEnd();
  }
  catch(Exception ex)
  { /*Show error message*/ }
  finally
  { tr.Close();}
}
catch(Exception ex)
{ /*Show error message*/ }

Хорошо, этот код - образец книги. Я не понимаю, почему используется вложенный блок try-catch.

Если

string content = tr.ReadToEnd();

идет не так, тогда внешний улов должен поймать исключение, верно? Так что я не вижу смысла в использовании дополнительного try-catch для этой строки!

Если вы видите здесь какие-либо заблуждения, я был бы рад, если бы вы могли указать на них!

Также есть ли случаи, когда целесообразно использовать вложенный try-catch?

Ответы [ 4 ]

3 голосов
/ 16 апреля 2011

Различия между вашим примером и аналогичным кодом, в котором есть только один внешний, catch:

1) Если внутренний блок выдает сообщение, то перед вызовом Close() печатается сообщение.Это может быть важно, если Close() также содержит ведение журнала.

2) Если внутреннее исключение выбрасывается и перехватывается, а затем в блоке finally Close() также выбрасывает, вы получаете дваисключения, и вы обрабатываете два исключения.Только с одним блоком catch, если Close() throws, то что произойдет дальше, может зависеть от языка, но вы не получите два сообщения об ошибке.Я ожидаю, что второе исключение заменит первое, но я не клянусь, что это происходит на всех языках с finally или даже на всех языках, которые я использовал ...

3) //Show error message это просто комментарий, он ничего не делает.Автор может иметь намерение показать сообщение об ошибке различное в двух разных случаях.Внутренний сказал бы: «Сбой чтения», а внешний сказал бы: «Не удается открыть файл».Или что-то типа того.Чтобы добиться этого только с одним блоком перехвата, вы можете установить и проверить флаг, указывающий на прогресс (что, вероятно, не делает код проще, чем два блока перехвата), или вы можете полагаться на само исключение, которое будет содержать соответствующее сообщение об ошибке (в этом случае удачи в интеграции вашей платформы локализации с функциями генерирования исключений во встроенные или сторонние библиотеки).

Обратите внимание, что даже если у вас есть только один улов, вам все равно нужно две попытки из-за finally.Это нехорошо:

try {
    TextReader tr = new StreamReader("filename");
    string content = tr.ReadToEnd();
} catch(Exception ex) {
    // show error message
} finally {
    tr.Close();
}

Поскольку, по внешнему виду этого языка, tr не будет находиться в области видимости в блоке finally, поэтому мы не можем закрыть его там.Мы должны закрыть его внутри блока, который занимается его созданием.Возможно, мы могли бы справиться с этим следующим образом:

TextReader tr = null;
try {
    tr = new StreamReader("filename");
    string content = tr.ReadToEnd();
} catch(Exception ex) {
    // show error message
} finally {
    if (tr != null) {
        tr.Close();
    }
}

Но это не сильно упрощает ситуацию по сравнению с исходным кодом, у нас все еще есть различия 2-3, с которыми приходится бороться, и теперь мыне обрабатывать исключения из Close() вообще.Так что для многих целей оригинальный код с несколькими try / catch был лучше.

2 голосов
/ 16 апреля 2011

если string content = tr.ReadToEnd(); идет не так, то внешний перехват должен ловить исключение правильно?

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

2 голосов
/ 16 апреля 2011

Один пример, который я использую, - это когда мне нужно обработать определенный тип исключения:

    try
    {

           //...
           //IMPORTANT CODE HERE
           //....
        try
        {
            // Read in non-existent file.
            using (StreamReader reader = new StreamReader("not-there.txt"))
            {
            reader.ReadToEnd();
            }
        }
        catch (FileNotFoundException ex)
        {
           //Do something important here
        }
       //...
       //MORE IMPORTANT CODE
       //...
    }
    catch(Exception ex) ///An Exception I'm not expecting
    { //oops...handle gracefully here
 }
1 голос
/ 16 апреля 2011

Вы хотите поймать исключение как можно раньше.Это плохая практика, чтобы позволить вещам пузыриться к внешнему исключению.Помните правило: терпите неудачу рано, часто терпите неудачу.

...