C# → Ошибки и обработка исключений

Исключение является экземпляром класса, который был явно и неявно унаследован от базового класса System.Exception.

Переменные, объявленные в блоке try выходят из видимости, когда управление предается в блок catch или finally. По окончании блока try, даже если ничего не произошло (ошибка не возникла), управление автоматически передается в блок finally, который должен содержать инструкции для освобождения ресурсов.

При обнаружении ошибки код осуществляет генерацию исключения (создание экземпляра класса исключения) и выдает его следующим образом:

throw new IndexOutOfRangeException(“Вы ввели: ” + userInput);

Как только компилятор встречает оператор throw внутри блока try, он немедленно ищет соответствующий блок catch.

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

Оператор throw может находиться в любом методе, вызванном во время выполнения блока try, — оно не обязано располагаться в том же самом методе, в котором определен блок try

Обработчики исключений для производного класса (IndexOutOfRangeException) должны идти раньше, чем для базового (Exception) (!)

Если обработчик catch записан как: catch { … } то это значит, что он отвечает за любой код (за любое возникшее исключение), в том числе написанным не на C# или не управляемым.

То, что в качестве исключений могут быть переданы только экземпляры класса, производного от System.Exception является требованием C#.

 while(true)  // бесконечный цикл
            {
                Console.Write("Выберите пункт меню от 0 до 5 или [Enter] для выхода: ");
                string userInput = Console.ReadLine();
                if (userInput == "") {Console.WriteLine("Вы нажали [Enter] значт выходим..."); break; }
                try
                {
                    int x = int.Parse(userInput);
                    switch (x)
                    {
                        case 0: Console.WriteLine("Выбран пункт 0"); break;
                        case 1: Console.WriteLine("Выбран пункт 1"); break;
                        case 2: Console.WriteLine("Выбран пункт 2"); break;
                        case 3: Console.WriteLine("Выбран пункт 3"); break;
                        case 4: Console.WriteLine("Выбран пункт 4"); break;
                        case 5: Console.WriteLine("Выбран пункт 5"); break;
                        default: throw new IndexOutOfRangeException(); break;
                    }
                }
                catch (IndexOutOfRangeException e)
                {
                    Console.WriteLine("Неверное значение. Выберити цифру от [0..5]");
                }
                catch (FormatException e)
                {
                    Console.WriteLine("Ошибка преобразования, возможно вы ввели строку...");
                }
                catch (Exception e)
                {
                    Console.WriteLine("Еще какая-то ошибка");
                }
                catch  {} // обработчик неуправляемого кода и кода на другом языке
            }

Свойства и методы System.Exception

if (ErrorCondition == true) {
                Exception myException = new ClassMyException("Help!");
                myException.Source = "Название приложения";
                myException.HelpLink = "myHelpFile.txt";
                throw myException; }

В коде не нужно генерировать исключения от общего класса System.Exception – он не дает представления о природе ошибочного состояния (!). В иерархии существует два важных класса:

SystemException – предназначен для исключений, обычно генерируемых средой исполнения .NET, или исключений имеющих общую природу и могут быть сгенерированы практически любым приложением. Подкласс представляет как фатальные, так и некритичные ошибки.

ApplicationException – представляет собой базу, предназначенную для любого класса исключений, определенного третьими лицами.

IOException (пространство имен System.IO) связаны с чтением и записью данных в файл.

StackOverflowException возникает тогда, когда участок памяти отведенный под стек, заполняется до отказа. Переполнение стека может возникнуть например в том случае, когда метод начинает рекурсивно вызвать самого себя. Обычной причиной появления EndOfStreamException является попытка чтения за границами файла. Переполнение OverflowException возникает, например при попытке привести int, содержащий -40 к типу uint в контексте checked.

Вложенные боли try используются по двум причинам:

— с целью изменения типа сгенерированного исключения (использование свойства InnerException, которое содержит ссылку на любое сгенерированное исключение);

— обработка разных исключений в разных участках кода.

Определение собственных классов исключений

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

class LandLineSpyFoundException : ApplicationException
    {
        public LandLineSpyFoundException(string spyName) : base("шпийон"+spyName) { }
        public LandLineSpyFoundException(string spyName, Exception innerException)
            : base(spyName, innerException) { }
    }