Для чего используется блок finally в C#?

«Для чего используется блок finally в C#?» — вопрос из категории C# Core, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Блок finally используется в конструкции try-catch-finally для гарантированного выполнения кода очистки или финализации независимо от того, как был завершён блок try — нормально, через исключение или даже через оператор return.

Основное назначение — освобождение неуправляемых или критических ресурсов: закрытие файлов, сетевых соединений, графических дескрипторов, чтобы избежать утечек.

Пример (паттерн до C# 8.0):

FileStream fileStream = null;
try
{
    fileStream = File.OpenRead("data.bin");
    // Работа с файлом, которая может вызвать IOException
    var data = new byte[100];
    fileStream.Read(data, 0, 100);
    // Даже return здесь не отменит finally!
    // return;
}
catch (IOException ex)
{
    Console.WriteLine($"Ошибка чтения файла: {ex.Message}");
    // Исключение будет проброшено ДАЛЬШЕ, но finally выполнится ПРЕЖДЕ.
    throw;
}
finally
{
    // Этот код выполнится ВСЕГДА:
    // 1. После успешного завершения try.
    // 2. После обработки исключения в catch.
    // 3. Даже если исключение не было перехвачено (после catch).
    // 4. При выходе из try через return, break, continue.
    fileStream?.Dispose();
    Console.WriteLine("Ресурс файла освобождён.");
}

Современная альтернатива (using statement): Для объектов, реализующих IDisposable, блок finally для вызова .Dispose() обычно инкапсулируется в оператор using, что является синтаксическим сахаром для той же конструкции try-finally.

using (var fileStream = File.OpenRead("data.bin"))
using (var reader = new StreamReader(fileStream))
{
    // Работа с reader
} // Dispose() будет вызван автоматически здесь, в неявном блоке finally

Важно: finally не выполнится только в исключительных случаях: аварийное завершение процесса (Environment.FailFast), фатальное исключение (например, StackOverflowException, OutOfMemoryException в некоторых ситуациях) или бесконечный цикл в блоке try.