Как обработать ошибку — try, catch и finally
Console.Write("Делимое: ");
string a = Console.ReadLine() ?? "";
Console.Write("Делитель: ");
string b = Console.ReadLine() ?? "";
try
{
int x = int.Parse(a);
int y = int.Parse(b);
Console.WriteLine($"Частное: {x / y}");
}
catch (FormatException)
{
Console.WriteLine("Нужно ввести целые числа");
}
catch (DivideByZeroException)
{
Console.WriteLine("На ноль делить нельзя");
}
finally
{
Console.WriteLine("Готово");
}Делимое: 10
Делитель: 0
На ноль делить нельзя
ГотовоИсключение — сигнал об ошибке во время работы программы: строку не удалось перевести в число, файла нет, делитель равен нулю. Если его не поймать, программа останавливается с сообщением вроде Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.
try { ... }— код, в котором может случиться ошибка.catch (Тип) { ... }— что делать при ошибке этого типа. Программа продолжает работу после всей конструкции.finally { ... }— выполняется всегда: и после успеха, и после ошибки. Сюда ставят то, что нужно сделать в любом случае, например закрыть файл.
Как только в try случилась ошибка, остальные его строки пропускаются, и выполнение переходит в подходящий catch.
Текст ошибки и общий catch
У каждого исключения есть свойство Message — описание ошибки. А catch (Exception ex) ловит любое исключение:
try
{
int[] a = new int[3];
a[5] = 1;
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка: {ex.Message}");
}Ошибка: Index was outside the bounds of the array.Общий catch (Exception) ставят последним: блоки проверяются сверху вниз, и после общего до частных дело не дойдёт — компилятор так и скажет (ошибка CS0160).
Своё исключение: throw
Метод может сам сообщить об ошибке через throw:
try
{
CheckAge(25);
CheckAge(-5);
}
catch (ArgumentException ex)
{
Console.WriteLine($"Ошибка: {ex.Message}");
}
static void CheckAge(int age)
{
if (age < 0)
{
throw new ArgumentException("возраст не может быть отрицательным");
}
Console.WriteLine($"Возраст: {age}");
}Возраст: 25
Ошибка: возраст не может быть отрицательнымЧастые готовые типы: ArgumentException (неверный аргумент), ArgumentOutOfRangeException (вне допустимого диапазона), InvalidOperationException (сейчас так делать нельзя). Все исключения наследуют класс Exception, поэтому catch (Exception) ловит их все.
Подводные камни
- Пустой
catch.catch { }молча проглатывает ошибку: программа работает дальше с неверными данными, а причину уже не найти. Хотя бы выведитеex.Message. - Исключения вместо проверок. Если неверный ввод — обычное дело, проверяйте заранее:
int.TryParseвместоtry { int.Parse(...) }(справка Как перевести строку в число). Исключения — для действительно неожиданных ситуаций. - Слишком большое число в
int.Parseдаёт неFormatException, аOverflowException— его тоже стоит ловить или использоватьTryParse. - Деление дробных на ноль исключения не даёт:
1.0 / 0— это бесконечность, а0.0 / 0— особое значение NaN («не число»). ИсключениеDivideByZeroExceptionбывает только у целых. - Чтобы передать пойманное исключение дальше, пишите
throw;, а неthrow ex;— так сохранится место, где оно возникло.