Зачем использовать наконец в C #?

189

Все, что находится внутри блоков finally, выполняется (почти) всегда, так в чем же разница между заключением в него кода или его закрытием?

Родриго
источник
3
Что ты имеешь в виду, оставляя это открытым?
Рамеш
5
И что вы подразумеваете под "(почти)"?
Беска
49
Если вы отключите шнур питания, когда машина выполняет предложение try, предложение finally не будет вызвано.
Dour High Arch
5
лол, да, это правда, но ты не можешь на самом деле код для этого, не так ли?
Эд С.
2
@Ed: использовать транзакции. Ваше предложение try должно сделать какое-то временное изменение или изменение в памяти, которое может быть сохранено в одном элементарном изменении в предложении finally. Это редко легко и может потребовать специального оборудования.
Dour High Arch

Ответы:

405

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

Теперь, я думаю, ваш вопрос, почему вы должны сделать это:

try
{
    doSomething();
}
catch
{
    catchSomething();
}
finally
{
    alwaysDoThis();
}

Когда вы можете сделать это:

try
{
    doSomething();
}
catch
{
    catchSomething();
}

alwaysDoThis();

Ответ заключается в том, что код внутри вашего оператора catch часто перебрасывает исключение или прерывает текущую функцию. С последним кодом, "AlwaysDoThis ();" Вызов не будет выполнен, если код внутри оператора catch выдаст возврат или сгенерирует новое исключение.

Кевин Панг
источник
3
Хм. Очень похоже на то, что я сказал, но яснее и точнее. Определенно +1.
Беска
46
это относится и к «return» внутри блока try {}.
Лукас
4
на самом деле, он применяется даже без блока catch {} (просто попробуйте / наконец, чтобы всплыли исключения)
Лукас
лучше, чем у меня, был на работе и не хотел тратить десять минут, отвечая на него подробно. +1
Мэтт Бриггс
2
Да, это было именно то, что я имел в виду: D Теперь я это понимаю.
Родриго
62

Большинство преимуществ использования try-finally уже было указано, но я подумал, что добавлю это:

try
{
    // Code here that might throw an exception...

    if (arbitraryCondition)
    {
        return true;
    }

    // Code here that might throw an exception...
}
finally
{
    // Code here gets executed regardless of whether "return true;" was called within the try block (i.e. regardless of the value of arbitraryCondition).
}

Такое поведение делает его очень полезным в различных ситуациях, особенно когда вам необходимо выполнить очистку (утилизировать ресурсы), хотя в этом случае часто лучше использовать блок using .

нолдорин
источник
2
Это буквально единственная причина, по которой я наконец-то использую
Кристофер Таунсенд,
12

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

 SqlConnection myConn = new SqlConnection("Connectionstring");
        try
        {
            myConn.Open();
            //make na DB Request                
        }
        catch (Exception DBException)
        {
            //do somehting with exception
        }
        finally
        {
           myConn.Close();
           myConn.Dispose();
        }

если вы не хотите отлавливать ошибку, используйте

 using (SqlConnection myConn = new SqlConnection("Connectionstring"))
        {
            myConn.Open();
            //make na DB Request
            myConn.Close();
        }

и объект подключения будет удален автоматически при возникновении ошибки, но вы не фиксируете ошибку

Боб Дворник
источник
2
Dispose () также закроет () соединение, не нужно вызывать оба. Close () НЕ Dipose (), вы можете снова открыть соединение.
Лукас,
Хорошо, спасибо за упоминание об использовании. Я бы ответил, в противном случае.
Дэн Розенстарк
11

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

Мэтт Бриггс
источник
7

Наконец, операторы могут выполняться даже после возврата.

private int myfun()
{
    int a = 100; //any number
    int b = 0;
    try
    {
        a = (5 / b);
        return a;
    }
    catch (Exception ex)
    {
        Response.Write(ex.Message);
        return a;
    }

 //   Response.Write("Statement after return before finally");  -->this will give error "Syntax error, 'try' expected"
    finally
    {
      Response.Write("Statement after return in finally"); // --> This will execute , even after having return code above
    } 

    Response.Write("Statement after return after finally");  // -->Unreachable code
}
Пратик Гупта
источник
7

finally, как в:

try {
  // do something risky
} catch (Exception ex) {
  // handle an exception
} finally {
  // do any required cleanup
}

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

Это делает его идеальным для таких вещей, как освобождение ресурсов, соединений БД, файловых дескрипторов и т. Д.

Дэвид Альперт
источник
3
Все эти примеры обычно лучше использовать с блоком using, но это не умаляет ваш ответ.
Джоэл Коухорн
4

Я объясню использование наконец с исключением чтения файлов Пример

  • без использования, наконец,
try{

  StreamReader strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
  Console.WriteLine(strReader.ReadeToEnd());
  StreamReader.Close();
}
catch (Exception ex)
{
  Console.WriteLine(ex.Message);
}

В приведенном выше примере, если файл с именем Data.txt отсутствует, будет сгенерировано исключение, которое будет обработано, но вызываемый операторStreamReader.Close(); никогда не будет выполнен.
Из-за этого ресурсы, связанные с читателем, так и не были выпущены.

  • Чтобы решить вышеуказанную проблему, мы используем, наконец,
StreamReader strReader = null;
try{
    strReader = new StreamReader(@"C:\Ariven\Project\Data.txt");
    Console.WriteLine(strReader.ReadeToEnd());
}
catch (Exception ex){
    Console.WriteLine(ex.Message);
}
finally{
    if (strReader != null){
        StreamReader.Close();
    }
}

Удачного кодирования :)

Примечание: «@» используется для создания дословной строки, чтобы избежать ошибки «Нераспознанная escape-последовательность». Символ @ означает буквальное прочтение этой строки, иначе не интерпретируйте управляющие символы.

Аривен Надар
источник
2

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

Крис Доггетт
источник
2

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

Например:

try
{
    // exception (or not)
}
finally
{
    // clean up always
}
Марком
источник
Если исключение не перехвачено, выполнение блока finally зависит от того, выберет ли операционная система запуск операции исключения.
Викас Верма
2

Блок finally полезен для очистки любых ресурсов, выделенных в блоке try, а также для запуска любого кода, который должен выполняться, даже если есть исключение. Управление всегда передается блоку finally независимо от выхода из блока try.

cgreeno
источник
1

Ааа ... Я думаю, я понимаю, что вы говорите! Заняло у меня секунду ... вы задаетесь вопросом "зачем размещать его в блоке finally, а не после блока finally и полностью вне try-catch-finally".

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

Beska
источник
1

Поток управления в блоке «В конце» идет после блока «Пробовать» или «Поймать».

[1. First Code]
[2. Try]
[3. Catch]
[4. Finally]
[5. After Code]

с исключением 1> 2> 3> 4> 5, если 3 имеет оператор Return 1> 2> 3> 4

без исключения 1> 2> 4> 5, если 2 имеет оператор возврата 1> 2> 4

Ранальд Фонг
источник
0

Как указано в документации :

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

Также стоит прочитать это , в котором говорится:

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

Таким образом, ясно, что код, который находится в finallyпредложении, будет выполнен, даже если в предыдущем catchпредложении был returnоператор.

Nexaspx
источник