Навіщо використовувати нарешті в C #?


189

Що б там не було, нарешті, блоки виконуються (майже) завжди, тож яка різниця між тим, що вкладати в нього код або залишати його незакритим?


3
Що ви маєте на увазі, залишаючи це незакритим?
Рамеш

5
А що ви маєте на увазі під «(майже)»?
Беська

49
Якщо витягніть шнур живлення, поки машина виконує спробу-пункт, остаточне застереження не буде викликано.
Dour High Arch

5
хаха, так, це правда, але ти не можеш насправді кодувати це?
Ред С.

2
@Ed: Використовуйте транзакції. У вашому пробному пункті повинно бути внесено якесь тимчасове або в пам'яті зміна, яке може зберігатися в одній, атомній, зміні остаточно. Це рідко легко і може знадобитися спеціальне обладнання.
Dour High Arch

Відповіді:


405

Код всередині остаточного блоку буде виконуватися незалежно від того, існує чи ні. Це дуже зручно, коли справа стосується певних функцій побутової роботи, які потрібно завжди виконувати, як з'єднання для закриття.

Тепер я здогадуюсь, що ваше питання - чому ви повинні робити це:

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

Коли ви можете це зробити:

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

alwaysDoThis();

Відповідь полягає в тому, що багато разів код всередині вашої заяви про вилов або повторно скине виняток, або вирветься з поточної функції. З останнім кодом, "alwaysDoThis ();" виклик не виконуватиметься, якщо код всередині оператора вилову повертає або викидає новий виняток.


3
Хм. Дуже схоже на те, що я сказав, але чіткіше і точніше. Визначений +1.
Беска

46
це стосується і "повернення" всередині блоку try {}.
Лукас

4
насправді він застосовується навіть без блоку {catch {} (просто спробуйте / нарешті, пускаючи виключення)
Лукас

краще, ніж я, працював і не хотів витрачати десять хвилин, відповідаючи на це детально. +1
Метт Бріггс

2
Так, це було саме те, що я мав на увазі: D Тепер я це розумію.
Родріго

62

Більшість переваг використання спробу-нарешті вже було вказано, але я подумав, що додам це:

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).
}

Така поведінка робить її дуже корисною в різних ситуаціях, особливо, коли вам потрібно проводити очищення (розпоряджатися ресурсами), хоча блок використання в цьому випадку часто краще.


2
Це буквально єдина причина, яку я остаточно використовую
Крістофер Таунсенд

12

будь-який час, коли ви використовуєте керовані запити коду, такі як зчитувачі потоків, запити db тощо; і ви хочете зловити виняток, тоді використовуйте спробуйте catch нарешті та закрийте потік, зчитувач даних тощо, нарешті, якщо ви цього не зробите, коли з’єднання не закривається, це справді погано із запитами db

 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 () НЕ розпоряджається (), ви можете відновити з'єднання.
Лукас

Приємно, дякую за згадування про використання. Я мав би відповісти, інакше.
Дан Розенстарк

11

Тому що, нарешті, буде виконано, навіть якщо ви не обробляєте виняток у блоці улов.


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блоку, незалежно від того, чи викинув випробувальний блок виняток.

Це робить його ідеальним для таких речей, як звільнення ресурсів, db-з'єднання, ручки файлів тощо.


3
Усі ці приклади, як правило, краще подавати з використанням блоку, але це насправді не погіршує вашу відповідь.
Joel Coehoorn

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();
    }
}

Щасливе кодування :)

Примітка: "@" використовується для створення дослівного рядка, щоб уникнути помилки "Нерозпізнаної послідовності відходу". Символ @ означає читати цей рядок буквально, а не інтерпретувати контрольні символи інакше.


2

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


2

Іноді ви не хочете обробляти виняток (немає блоку захоплення), але хочете виконати якийсь код очищення.

Наприклад:

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

Якщо виняток не вловлюється, виконання остаточного блоку залежить від того, чи операційна система вирішить запустити операцію розмотування виключення.
Вікас Верма

2

Зрештою, блок цінний для очищення будь-яких ресурсів, виділених у блоці спробу, а також для запуску будь-якого коду, який потрібно виконати, навіть якщо є виняток. Контроль завжди передається остаточному блоку, незалежно від того, як виходить блок спробу.


1

А-а ... я думаю, я бачу, що ти кажеш! Зайняв мене на секунду ... Вам цікаво, "чому розмістити його в остаточному блоці замість того, щоб після остаточно блокувати і зовсім поза межами" пробувати-нарешті ".

Наприклад, це може бути тому, що ви зупиняєте виконання, якщо ви кидаєте помилку, але все одно хочете очистити ресурси, наприклад, відкриті файли, підключення до бази даних тощо.


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

Як зазначено в документації :

Загальне використання улову і, нарешті, разом - це отримання та використання ресурсів у пробному блоці, вирішення виняткових обставин у блоці вилову та звільнення ресурсів у остаточному блоці.

Варто також прочитати це , де зазначено:

Після того, як буде знайдено відповідне застереження щодо вилову, система готується передати управління першому оператору застереження про вилов. Перед тим, як розпочнеться виконання застереження, система спочатку виконує для того, щоб будь-які остаточні пропозиції, які були пов'язані з операторами спробу, вклали більше, ніж ті, що вивели виняток.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.