Что такое Runtime error (ошибка времени выполнения) в C#?

Ответ

Runtime error (ошибка времени выполнения) — это исключение, которое возникает во время исполнения программы, когда синтаксически корректный код приводит к недопустимой операции. В отличие от ошибок компиляции, компилятор не может их обнаружить на этапе сборки.

Распространённые примеры исключений времени выполнения в .NET:

  • NullReferenceException: Попытка обращения к члену объекта, который равен null.
  • IndexOutOfRangeException: Попытка доступа к элементу массива или коллекции по индексу за её пределами.
  • DivideByZeroException: Деление целочисленного значения на ноль.
  • InvalidCastException: Неудачное приведение типа во время выполнения.
  • StackOverflowException: Бесконечная рекурсия, исчерпавшая стек вызовов.
  • OutOfMemoryException: Нехватка доступной памяти для выделения нового объекта.

Пример кода, вызывающего ошибку времени выполнения:

int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]); // IndexOutOfRangeException

Обработка ошибок времени выполнения: Для обработки таких ситуаций и предотвращения аварийного завершения программы используется конструкция try-catch-finally.

try
{
    int divisor = 0;
    int result = 10 / divisor; // Потенциальный DivideByZeroException
}
catch (DivideByZeroException ex)
{
    // Логируем и обрабатываем конкретную ошибку
    Console.WriteLine($"Ошибка: {ex.Message}");
    // Возвращаем значение по умолчанию или пробрасываем исключение выше
}
catch (Exception ex) // Общий обработчик для других исключений
{
    Console.WriteLine($"Произошла непредвиденная ошибка: {ex.Message}");
}
finally
{
    // Этот блок выполнится всегда, даже если было исключение
    Console.WriteLine("Операция завершена (успешно или с ошибкой).");
}

Профилактика: Лучшая практика — предвосхищать возможные ошибки с помощью проверок (валидация входных данных, проверка на null, использование безопасных операторов как ?. и ??).

Ответ 18+ 🔞

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

Представь, ты написал код, скомпилировал — всё чисто, синтаксис идеальный. Запускаешь, а он тебе как даст: «На ноль делить нельзя, мудила!». Это и есть Runtime error. Компилятор-то не знал, что в переменной divisor окажется ноль, он видел просто переменную. А вот когда дело дошло до дела — пиздец.

Самые популярные грабли, на которые наступают все:

  • NullReferenceException — классика жанра. Пытаешься что-то сделать с объектом, а он null. Как будто звонишь другу, а на том конце тишина и трубку не берут. «Вызови метод у этого объекта!» — «А у какого, сука? Его же нет!».
  • IndexOutOfRangeException — ещё одна любимица. Массив на три элемента, а ты лезешь за пятым. Это как в очереди из трёх человек спросить: «Эй, пятый, ты чё стоишь?». Тебе сразу в еблет дадут, то есть исключение кинут.
  • DivideByZeroException — тут всё ясно. Математика, 6 класс. Делить на ноль нельзя. А ты взял и поделил. Ну и какого хуя ты ожидал?
  • InvalidCastException — решил, что в переменной object лежит строка, а там на самом деле число. Попытался привести — получи по ебалу. Это как пытаться надеть трусы на голову и назвать это шапкой. Не катит.
  • StackOverflowException — это когда метод вызывает сам себя, а тот вызывает себя, и так до бесконечности. Память для вызовов (стек) кончается, и всё, пиздец, приехали. Рекурсия без условия выхода — верный путь в ад.
  • OutOfMemoryException — программа так захавала памяти, что системе больше нечего дать. Создавал объекты в цикле и забыл их удалять? Жди эту гостью.

Вот, смотри, как просто устроить катастрофу:

int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]); // IndexOutOfRangeException

Всё. Программа аварийно завершится. Пользователь в панике.

Что делать, чтобы не выглядеть идиотом? Ловить эти ошибки!

Для этого есть try-catch-finally. Это как страховочная сетка под канатоходцем.

try
{
    // Здесь мы идём по канату без страховки. Опасный код.
    int divisor = 0;
    int result = 10 / divisor; // Потенциальный DivideByZeroException
}
catch (DivideByZeroException ex) // Ловим конкретно деление на ноль
{
    // Всё, поймали. Не упали, а мягко приземлились в эту секцию.
    Console.WriteLine($"Ошибка: {ex.Message}");
    // Тут можно сказать: «Сорян, на ноль делить нельзя, давай по-другому».
}
catch (Exception ex) // А это общая сетка. Сюда упадёт ВСЁ, что не поймали выше.
{
    Console.WriteLine($"Произошла непредвиденная хуйня: {ex.Message}");
}
finally
{
    // Этот блок выполнится ВСЕГДА. Упал ты или нет. Без вариантов.
    // Типа, «операция завершена, можно убирать инструменты».
    Console.WriteLine("Операция завершена (успешно или с ошибкой).");
}

Но лучшая стратегия — не допускать этого вообще!

Не надейся только на try-catch. Это как лечить болезнь, а не предотвращать её. Золотое правило:

  1. Проверяй на null, прежде чем использовать объект. Или используй ?. (null-условный оператор).
  2. Смотри, не вылезаешь ли за границы массива.
  3. Проверяй знаменатель перед делением.
  4. Для приведения типов используй as или is, а не голый (Type).

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