Практическое руководство. Выполнение кода очистки с использованием блока finally

Оператор finally позволяет гарантировать, что необходимая очистка объектов, как правило, объектов, занимающих внешние ресурсы, возникает немедленно, даже при создании исключения. Примером подобной очистки является вызов Close для FileStream сразу после использования вместо ожидания сборки мусора, выполняемой для объекта средой CLR, следующим образом:

static void CodeWithoutCleanup()
{
    FileStream? file = null;
    FileInfo fileInfo = new FileInfo("./file.txt");

    file = fileInfo.OpenWrite();
    file.WriteByte(0xF);

    file.Close();
}

Пример

Чтобы преобразовать предыдущий код в оператор try-catch-finally, код очистки отделяется от рабочего кода следующим образом:

static void CodeWithCleanup()
{
    FileStream? file = null;
    FileInfo? fileInfo = null;

    try
    {
        fileInfo = new FileInfo("./file.txt");

        file = fileInfo.OpenWrite();
        file.WriteByte(0xF);
    }
    catch (UnauthorizedAccessException e)
    {
        Console.WriteLine(e.Message);
    }
    finally
    {
        file?.Close();
    }
}

Так как исключение в блоке try может возникнуть в любой момент до вызова OpenWrite() или может произойти сбой самого вызова OpenWrite(), мы не можем гарантировать, что файл, который мы попытаемся закрыть, будет в это время открыт. Блок finally добавляет проверку того, что объект FileStream — не null, перед вызовом метода Close. Без проверки null блок finally может вызывать собственное исключение NullReferenceException, однако вызова исключений в блоках finally следует по возможности избегать.

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

См. также