Зачем использовать Наконец в Try ... Catch - PullRequest
45 голосов
/ 21 июля 2009

Я вижу, что Finally в Try .. Catch всегда будет выполняться после любых частей выполнения блока try catch.

Разве можно просто пропустить раздел Finally и запустить его после блока try catch?

Пример 1, Try ... Catch ... Наконец ... End Try

    Try
        'Do something
    Catch ex As Exception
        'Handle exception
    Finally
        'Do cleanup
    End Try

Пример 2, Попробуй ... Поймай ... Конец Попробуй ... Сделай наконец что-то вне

    Try
        'Do something
    Catch ex As Exception
        'Handle exception
    End Try
    'Do cleanup

Ответы [ 14 ]

66 голосов
/ 21 июля 2009

Да, это другое. Наконец всегда будет работать (исключая сбой программы). Если функция выходит из блока try catch, или в try или catch генерируется другая ошибка, finally все равно будет выполнено. Вы не получите эту функциональность без использования оператора finally.

12 голосов
/ 21 июля 2009

Код с четырьмя переключателями:

  • возврат в TRY
  • Возврат в CATCH
  • Бросок в CATCH
  • Готово CATCH

    private void checkFinally()
    {
        try
        {
            doFinally();
        }
        catch
        {
            Console.WriteLine(" Breaking news: a crash occured. ");
        }
    }
    
    private void doFinally()
    {
        Console.WriteLine(" ");
        Console.Write("Here goes: " 
            + (radioReturnInTry.Checked ? "2. Return in try: " 
                    : (radioReturnInCatch.Checked? "3. Retrun in catch: "
                        : (radioThrowInCatch.Checked? "4. Throw in catch: "
                            : "1. Continue in catch: "))) );
        try
        {
            if (radioReturnInTry.Checked)
            {
                Console.Write(" Returning in try. ");
                return;
            }
            Console.Write(" Throwing up in try.  ");
            throw new Exception("check your checkbox.");
        }
        catch (Exception ex)
        {
            Console.Write(" ...caughtcha! ");
            if (radioReturnInCatch.Checked)
            {
                Console.Write("Returning in catch. ");
                return;
            }
            if (radioThrowInCatch.Checked)
            {
                Console.Write(" Throwing up in catch. ");
                throw new Exception("after caught");
            }
        }
        finally { Console.Write(" Finally!!"); }
        Console.WriteLine(" Done!!!"); // before adding checkboxThrowInCatch, 
        // this would never happen (and was marked grey by ReSharper)
    
    }
    

Выход:

  • Здесь идет речь: 1. Продолжить в улове: подбрасывать в попытке. ... caughtcha! В заключение!! Готово !!!
  • Здесь идет: 2. Возврат в попытке: Возврат в попытке. Наконец !!
  • Здесь идет речь: 3. Перезапуск в улове: подбрасывание в попытке. ... caughtcha! Возвращаясь в улов. В заключение!!
  • Вот так: 4. Бросок в улове: Бросок в попытке. ... caughtcha! Рвота в улове. В заключение!! Последние новости: произошел сбой.

Подведем итог: Наконец заботится о двух вещах:

  1. кода, который вернул в попытке или в перехвате.
  2. Или, если у вас было исключение в попытке, И БРОСИТЬ исключение в улове,
  3. или, если у вас возникла исключительная ситуация в попытке, И НЕ УТОЧНЯЛО это исключение,

Наконец, чтобы подвести итог "НАКОНЕЦ" : Наконец не делает ничего особенного, если вы пытались, и

  1. НЕ ВОЗВРАЩАЕТСЯ,
  2. и поймал все исключения во время испытания, а затем
  3. также НЕ ВОЗВРАЩАЕТСЯ в улове и
  4. НЕ ВЫБРАЛ или не выдавал код.

И последнее, но не менее важное (наконец): Если у вас есть исключение в вашем коде, которое вы НЕ ЗАХВАТИЛИ, ваш код будет летать, БЕЗ ДОСТИГНУТИЯ.

Надеюсь, это понятно. (Теперь это для меня ...)

Моше

7 голосов
/ 21 июля 2009

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

Невозможно выйти из блока try, не выполнив его блок finally. Если блок finally существует, он всегда выполняется. (Это утверждение верно для всех намерений и целей. Существует способ выйти из блока try без выполнения блока finally. Если код выполняет System.exit (0); из блока try приложение завершается без окончательного кода Выполнение. С другой стороны, если вы отключите компьютер во время блока try, то finally также не будет выполнено.)

Основное назначение - утилизация предметов. Это будет полезно, когда вы хотите закрыть пользователя определенные ресурсы, такие как файл, открытые ресурсы (db stmts).

Редактировать

Также, наконец, не будет выполняться после исключения переполнения стека.

5 голосов
/ 21 июля 2009

Разница заключается в том, что код в блоке try выдает исключение, которое не перехватывается блоком catch.

Обычно блок catch ловит определенный тип исключения и пропускает что-либо еще. В этом случае блок finally все еще будет работать.

Блок finally также будет запущен, если код в блоке try return s.

3 голосов
/ 21 июля 2009

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

2 голосов
/ 23 мая 2013

Наконец, следует использовать все, что нужно сделать, чтобы система работала согласованно. Обычно это означает высвобождение ресурсов

Наконец, всегда выполняется, независимо от того, какое исключение было выброшено. Он должен использоваться для освобождения ресурсов в следующих случаях:

  • Завершить соединение
  • Закрыть обработчик файла
  • Свободная память
  • Закрыть соединение с базой данных

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

// With finally                  |  //Without finally
try{                             |  try{  
  send_message()                 |    send_message() 
} catch(NetworkError){           |  } catch(NetworkError){ 
  deal_with_exception()          |    deal_with_exception()
} finally {                      |  }
  finalizes_connection()         |  finalizes_connection() 
}                                |

Единственное различие обоих кодов состоит в том, что то, что удерживается в блоке try, вызывает исключение, которое не является NetworkError, например, MethodNotFound. В первом случае будет вызван метод finalizes_connection(), а во втором - нет.

Соединение, естественно, осуществляется через несколько программ. Так что же происходит в случае MethodNotFound исключения для другой программы? В первом случае ваша программа завершит соединение, а другая программа будет счастлива. Во втором случае другая программа может ждать вашего ответа вечно. Что если другая программа может получить только одно соединение за раз? Вы только что прослушали другую программу.

Это также относится к файлу, например, который вы открыли, и другие программы не смогут открыть для чтения (в Windows). Что касается памяти, она никогда не освобождается, и теперь у вас есть утечка памяти.

2 голосов
/ 21 июля 2009

Блок finally будет выполняться независимо от того, выходит ли функция из-за исключения. (есть некоторые исключения из этого правила, для получения дополнительной информации см. вопрос об этом стеке).

Например:

Try
    'Do something
Catch ex As Exception
    if 'Some Condition
       throw ex
    else
       'Handle exception
Finally
    'Do cleanup
End Try

В этом случае блок finally будет по-прежнему выполняться, даже если вы можете выбросить исключение из функции.

Это хорошая практика, потому что она гарантирует, что ваш код очистки всегда выполняется. Конечно, использование Resoource Acquisition Is Initialization идиома - гораздо более чистый способ обеспечения очистки ресурсов, но я не достаточно сведущ в VB.net, чтобы знать, возможно ли это сделать. *

1 голос
/ 23 июля 2009

Насколько я помню, я никогда не использовал блок try / catch / finally в своем коде .NET.

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

Таким образом, на среднем уровне вы чаще будете видеть try / finally (или оператор "using"), чтобы очистить ресурсы. И в try / catch в обработчике верхнего уровня на уровне презентации.

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

try
{
    ... do something
}
catch
{
   ... handle exception
}
finally
{
   ... cleanup
}

становится:

try
{
    DoSomethingAndCleanup();
}
catch
{
   ... handle exception
}

...
private void DoSomethingAndCleanup()
{
    try
    {
        ... do something
    }
    finally
    {
        ... cleanup
    }
}

ИМХО, это намного чище.

1 голос
/ 21 июля 2009

В дополнение к тому, что все остальные говорили, семантически я думаю, что они разные.

Код в блоке finally четко указывает, что вы выполняете задачи типа финализации для содержимого, содержащегося в try-catch. Я думаю, это облегчает чтение.

1 голос
/ 21 июля 2009

Выполнение очистки в блоке finally означает, что он запущен. Если блок catch не обрабатывает исключение (т. Е. Просто регистрирует его) или даже вызывает другое исключение, код в блоке finally все равно будет работать.

...