Почему, наконец, блок может не выполняться, когда выдается исключение - PullRequest
0 голосов
/ 10 февраля 2020

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

У меня есть следующий фрагмент кода:

using System;

public sealed class Program
{

    public static void Main()
    {
        try {
            int zero = 0;
            int i = 1/zero;
        } finally {
            Console.WriteLine("divide by zero"); //the line is never called
        }
    }
}

Я никогда не достигаю строки, которая выводит на консоль. Это означает, что я не смогу освободить ресурс в блоке finally в этом случае, за исключением того, что оно было сгенерировано внутри блока try.

Итак, я считаю, что есть две вещи: либо я что-то пропущено или комбинация try + finally не имеет прецедентов в C#. Второе утверждение имеет смысл, потому что я получу ту же функциональность, что и в приведенном выше коде, с кодом ниже:

using System;

public sealed class Program
{

    public static void Main()
    {
            int zero = 0;
            int i = 1/zero;

            Console.WriteLine("divide by zero"); //the line is never called
    }
}

Но я боюсь, что здесь что-то не хватает. Итак, кто-то может подтвердить, что комбинация бесполезна, или доказать, что это не так, пожалуйста?

ОБНОВЛЕНИЕ

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

enter image description here

Ответы [ 4 ]

8 голосов
/ 10 февраля 2020

Ваши предположения неверны (иногда) https://dotnetfiddle.net/hjqmOS

try-finally (C# Ссылка)

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

Есть случаи, когда он не запускается, хотя

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

Вот важная часть

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

1 голос
/ 11 февраля 2020

Я полагаю, это потому, что у вас есть VS, чтобы разбить необработанные ошибки и, следовательно, VS делает шаг к отображению исключения. Если вы скомпилируете его и запустите вручную в командной строке, я думаю, вы увидите «делить на ноль». Кроме того, вместо изменения настроек VS вы можете «обработать» ошибку и затем увидеть ожидаемое поведение.

Пример:

using System;

public sealed class Program
{

public static void Main()
{
    try
    {
        int zero = 0;
        int i = 1 / zero;
    }
    catch
    {

    }
    finally
    {
        Console.WriteLine("divide by zero"); 
    }
}
}
1 голос
/ 10 февраля 2020

try/catch/finally не имеет никакого отношения к освобождению ресурсов. Это строго поток приложения и конструкция обработки ошибок. Вы живете в управляемом коде, а сборщик мусора освобождает ресурсы. Эта конструкция делает следующее

try
{
    int zero = 0;
    int i = 1/zero;
}
catch (DividedByZeroException ex)
{
    Console.WriteLine(Exception handled);
    throw; // propagate ex to caller
}
finally
{
    Console.WriteLine("Method ended execution"); // called with or without exception
}
0 голосов
/ 15 февраля 2020

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

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

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

После выполнения всего кода во внутренних блоках finally выполняется код в блоке обработки обработки.

Таким образом, это означает, что в случае любого необработанного исключения блок finally вызываться не будет.

...