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

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

14 ответов

Решение

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

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

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

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

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

alwaysDoThis();

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

Большинство преимуществ использования 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.

Каждый раз, когда вы используете неуправляемые запросы кода, такие как потоковые считыватели, запросы БД и т. д.; и вы хотите перехватить исключение, затем использовать 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();
        }

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

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

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

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
}

finally, как в:

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

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

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

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

  • без использования, наконец,
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-последовательность". Символ @ означает буквальное прочтение этой строки, иначе не интерпретируйте управляющие символы.

Используя finally блок, вы можете очистить любые ресурсы, выделенные в try блок, и вы можете запустить код, даже если исключение происходит в try блок. Как правило, заявления finally Блокировка запуска, когда управление покидает оператор try. Передача контроля может произойти в результате нормального выполнения, выполнения break, continue, goto, or return заявление или распространения исключения из try заявление.

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

Обычно, когда необработанное исключение завершает приложение, независимо от того, finally блок запуска не важен. Однако, если у вас есть заявления в finally блок, который должен быть запущен даже в этой ситуации, одним из решений является добавление catch блокировать к try-finally заявление. Кроме того, вы можете поймать исключение, которое может быть брошено в try блок try-finally оператор выше по стеку вызовов. То есть вы можете перехватить исключение в методе, который вызывает метод, содержащий try-finally оператора, или в методе, который вызывает этот метод, или в любом методе в стеке вызовов. Если исключение не обнаружено, выполнение finally Блокировка зависит от того, выберет ли операционная система запуск операции исключения.

public class ThrowTestA
{
    static void Main()
    {
        int i = 123;
        string s = "Some string";
        object obj = s;

        try
        {
            // Invalid conversion; obj contains a string, not a numeric type.
            i = (int)obj;

            // The following statement is not run.
            Console.WriteLine("WriteLine at the end of the try block.");
        }
        finally
        {
            // To run the program in Visual Studio, type CTRL+F5. Then  
            // click Cancel in the error dialog.
            Console.WriteLine("\nExecution of the finally block after an unhandled\n" +
                "error depends on how the exception unwind operation is triggered.");
            Console.WriteLine("i = {0}", i);
        }
    }
    // Output: 
    // Unhandled Exception: System.InvalidCastException: Specified cast is not valid. 
    // 
    // Execution of the finally block after an unhandled 
    // error depends on how the exception unwind operation is triggered. 
    // i = 123
}

В следующем примере исключение из метода TryCast перехватывается в методе, расположенном дальше по стеку вызовов. C#

public class ThrowTestB
{
    static void Main()
    {
        try
        {
            // TryCast produces an unhandled exception.
            TryCast();
        }
        catch (Exception ex)
        {
            // Catch the exception that is unhandled in TryCast.
            Console.WriteLine
                ("Catching the {0} exception triggers the finally block.",
                ex.GetType());

            // Restore the original unhandled exception. You might not 
            // know what exception to expect, or how to handle it, so pass  
            // it on. 
            throw;
        }
    }

    public static void TryCast()
    {
        int i = 123;
        string s = "Some string";
        object obj = s;

        try
        {
            // Invalid conversion; obj contains a string, not a numeric type.
            i = (int)obj;

            // The following statement is not run.
            Console.WriteLine("WriteLine at the end of the try block.");
        }
        finally
        {
            // Report that the finally block is run, and show that the value of 
            // i has not been changed.
            Console.WriteLine("\nIn the finally block in TryCast, i = {0}.\n", i);
        }
    }
    // Output: 
    // In the finally block in TryCast, i = 123. 

    // Catching the System.InvalidCastException exception triggers the finally block. 

    // Unhandled Exception: System.InvalidCastException: Specified cast is not valid.
}

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

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

Например:

try
{
    // exception (or not)
}
finally
{
    // clean up always
}

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

Поток управления в блоке "Окончание" находится после блока "Пробовать" или "Поймать".

[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

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

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

Как упоминалось в документации:

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

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

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

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

Наконец-то блок

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

Недопустимо явно передавать исполнение в Finally блок.

Перенос исполнения из Finally Блок недействителен, кроме как через исключение.

Другие вопросы по тегам