Ответ
В C# для обработки нескольких типов исключений используются последовательные блоки catch. Ключевой принцип — располагать их в порядке от наиболее специфичных к наиболее общим, чтобы гарантировать корректный перехват.
Пример с несколькими блоками catch:
try
{
// Код, который может вызвать разные исключения
var data = File.ReadAllText("config.json");
var settings = JsonSerializer.Deserialize<Settings>(data);
}
catch (FileNotFoundException ex) // Наиболее специфичное
{
Console.WriteLine($"Файл конфигурации не найден: {ex.FileName}");
// Создаем файл с настройками по умолчанию
}
catch (JsonException ex)
{
Console.WriteLine($"Ошибка парсинга JSON: {ex.Message}");
// Используем дефолтные настройки
}
catch (IOException ex) // Более общее исключение ввода-вывода
{
Console.WriteLine($"Ошибка ввода-вывода: {ex.Message}");
}
catch (Exception ex) // Самый общий блок — должен быть последним
{
Console.WriteLine($"Непредвиденная ошибка: {ex.Message}");
throw; // Пробрасываем выше, если не можем обработать
}
finally
{
// Этот блок выполнится всегда, даже если было исключение
Console.WriteLine("Операция чтения конфигурации завершена.");
}
Дополнительные возможности:
-
Фильтры исключений (when): Позволяют добавить условие для входа в блок
catch.catch (Exception ex) when (ex.InnerException is SqlException) { // Обрабатываем только если внутреннее исключение — SqlException LogDatabaseError(ex.InnerException); } -
Перехват нескольких типов в одном блоке (C# 6.0+):
catch (ArgumentException or InvalidOperationException ex) { // Обрабатываем ArgumentException ИЛИ InvalidOperationException Console.WriteLine($"Некорректный аргумент или операция: {ex.Message}"); }
Практические рекомендации:
- Избегайте пустых блоков
catch. Это скрывает ошибки. - Используйте повторный выброс (
throw;), а неthrow ex;. Первый вариант сохраняет оригинальный стек вызовов. - Блок
finallyидеально подходит для освобождения ресурсов (закрытие файлов, соединений с БД).