![]() Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Обработка исключительных ситуаций
Лекция 9 Массивы в C#. Обработка исключительных ситуаций Базовый класс для массивов В языке C# массивы, как и типы данных, являются классами. Если объявить, например, целочисленный массив int[], то он автоматически наследуется от класса Array из пространства имён System. В классе Array определены несколько важных статических методов: 1. IndexOf() ‒ определяет индекс элемента в массиве. Если объект в массиве не найден, то метод вернет индекс наименьшего элемента в массиве минус единица. Индексы нумеруются с нуля, поэтому результатом будет -1; 2. Clear() ‒ этот метод предоставляет возможность удалить из массива определенное количество элементов. Например, чтобы из массива myArray удалить 5 элементов, начиная со 2-го, нужно записать: Array.Clear(myArray, 2, 5); 3. СоруТо() ‒ позволяет скопировать данные одного массива в другой; 4. LastIndexOf() ‒ находит последний индекс объекта в массиве, если в массив несколько раз добавлен указанный объект; 5. Reverse() ‒ переворачивает массив в обратном направлении; 6. Sort() ‒ сортирует массив. Класс также содержит свойство Length, которое позволяет определить количество элементов массива. Пример использования некоторых методов и свойств класса: int[] test = {10, 20, 1, 6, 15 }; // сортировка Console.WriteLine("Отсортированная версия: "); Array.Sort(test); foreach (int i in test) { Console.WriteLine(i); } // реверс элементов массива Console.WriteLine("Реверсная версия: "); Array.Reverse(test); foreach (int i in test) { Console.WriteLine(i); } // Удаление двух элементов массива Console.WriteLine("Текущий размер: {0}", test.Length); Array.Clear(test, 2, 2); Console.WriteLine("После удаления: {0}", test.Length); foreach (int i in test) { Console.WriteLine(i); } Невыровненные массивы До сих пор речь шла о ровных многомерных массивах. Если объявить двумерный массив в виде таблицы, то в каждой строке такого массива ровно столько элементов, сколько указано при создании, и это количество неизменно. Допустим, необходимо создать двумерный массив, у которого в первой строке 1 элемент, во второй строке 10 элементов, в третьей 5 и т. д. Такие массивы называются невыровненными. Невыровненный двумерный массив объявляется в виде: Тип_данных[] [] переменная; Инициализировать такой массив нужно только количеством строк, а количество колонок для каждой строки указывается отдельно. Например: int [][] jaggedArray = new int[10] []; jaggedArray[1] = new int[5]; jaggedArray[2] = new int[2]; jaggedArray[4] = new int[20]; В данном примере объявлена переменная jaggedArray, состоящая из 10 строк. После этого для отдельных строк задается явно количество элементов в строке. Количество элементов задано только для строк с индексами 1, 2 и 4. Остальные останутся нулевыми (не проинициализированными), и доступ к ним останется запрещенным. При попытке прочитать или изменить значения элементов в этих строках произойдёт ошибка. При обращении к элементам такого массива каждую размерность нужно указывать в отдельной паре квадратных скобок: jaggedArray[1][2] = 1; Ещё один пример работы с невыровненным массивом: int[][] jaggedArray = new int[10][]; // массив выделения памяти для каждой строки for (int i = 0; i < jaggedArray.Length; i++) { jaggedArray[i] = new int[i]; } // использование массива for (int i = 0; i < jaggedArray.Length; i++) { for (int j = 0; j < jaggedArray[i].Length; j++) { jaggedArray[i][j] = j; } Console.Write(jaggedArray[i][j]); } Console.WriteLine(); } Чтобы создать треугольный массив, после объявления невыровненного массива запускается цикл, который выполняется от нуля до количества элементов в массиве. Внутри цикла инициализируем очередную строку текущим значением счетчика в переменной i. Другие два цикла перебирают все строки массива и элементы в них. Значения этих элементов выводятся в консоль. Динамические массивы Все массивы, о которых ранее шла речь, обладают одним серьёзным недостатком – их размер фиксирован и определяется во время инициализации. Но в реальной жизни далеко не всегда известно, какого размера должен быть массив во время выполнения программы. Можно попытаться предсказать максимально возможный результат и выделить для его сохранения максимально возможное количество данных, но при этом тратится слишком много памяти и нет гарантии, что учтён действительно самый «неблагоприятный» вариант. Например, при написании программы, которая хранит количество машин на автостоянке, можно на всякий случай выделить место для 50 элементов в массиве. Но если на стоянке будет только одна машина, память для 49 элементов будет расходоваться впустую. В то же время, если стоянка вдвое расширится и сможет вмещать 100 машин, при добавлении 51-й машины в массив произойдёт ошибка – он будет переполнен. Проблема решается с помощью динамических массивов. Для работы с ними используется класс ArrayList, который позволяет динамически добавлять и удалять память для хранения очередного элемента массива и использует только такое количество памяти, сколько нужно. Пусть необходимо наделить класс Person (человек) возможностью хранения списка детей. Возможный вариант решения приведён ниже: ………………………………………………………………… ArrayList Children = new ArrayList(); public void AddChild(string firstName, string lastName) { Children.Add(new Person(firstName, lastName)); } public void DeleteChild(int index) { Children.RemoveAt(index); } public Person GetChild(int index) { return (Person)Children[index]; } ………………………………………………………………… Наиболее интересные методы и свойства класса ArrayList: 1. Count ‒ свойство, которое позволяет узнать количество элементов в массиве; 2. Add() ‒ добавление элемента, переданного в качестве параметра, в список; 3. Remove() ‒ удаление элемента, объект которого указан в качестве параметра. Если такой объект не найден в списке, то удаления не произойдет; 4. RemoveAt() ‒ удаление элемента с индексом, переданного в качестве параметра; 5. Clear() ‒ удаление содержимого списка. Класс ArrayList также наследует все свойства и методы базового класса Array.
Интерфейсы массивов Существуют несколько интерфейсов, которые позволяют по-разному работать с массивами. Несколько самых важных из них: 1. ICollection — коллекция определяет методы добавления элементов в массив, получения интерфейса перечисления элементов и определения количества элементов. Именно этот интерфейс используется для доступа к элементам массива таких компонентов, как ListView, ListBox и т. д; 2. IComparer – используется для сравнения элементов во время сортировки; 3. IDictionary – интерфейс, позволяющий реализовать доступ к элементам по ключу/значению. 4. IEnumerable — если класс реализует этот интерфейс, то объект этого класса можно использовать в операторе цикла foreach, т. е. он содержит необходимые методы, через которые можно перебирать элементы списка; 5. IList – если класс реализует этот интерфейс, то к элементам его массива можно обращаться по индексу.
Обработка исключительных ситуаций Предположим, программа должна выполнить следующие операции: открыть файл, записать в него информацию и закрыть файл. Если при выполнении программы пользователь, например, задал несуществующий путь для файла или указал в имени файла недопустимые символы, то вызов команды открытия файла завершится неудачей. При отсутствии какой-либо реакции на такую ситуацию программа может «обрушиться» Вообще говоря, к проблемам работы программы может привести несовершенство исходного кода или логики выполнения. Для таких случаев предусмотрен механизм обработки исключительных ситуаций. Предположим, в некотором классе определён метод MyMul, выполняющий деление двух чисел: double MyMul(int x, int y) { return x / y; } «Рискованным» моментом в коде является деление. Если значение параметра y будет равно нулю, при попытке деления компьютер сгенерирует ошибку. В данном примере для исключения возможности деления на нуль можно вставить в код условный оператор для проверки значения y на равенство нулю. При работе с дисками или с любыми другими ресурсами, зависящими от окружения, желательно задействовать механизм обработки исключений. Категории ошибок, которые могут вызывать исключительные ситуации: 1. Ошибки при работе с ресурсами компьютера, необходимыми программе. 2. Ошибки логики приложений. 3. Пользовательские ошибки. Исключения в C# строятся на основе ключевых слов try, catch, throw и finally, а также на основе классов исключительных ситуаций. Базовый класс для исключений – Exception из пространства имён System. Самые интересные свойства/методы в классе Exception: 1) InnerException – информация о внутренних исключениях, которые стали причиной данной исключительной ситуации; 2) Message – короткое текстовое описание ошибки; 3) Source – имя сборки, сгенерировавшей исключение 4) StackTrace – строка, содержащая последовательность вызовов, которые привели к ошибке. Это свойство может быть полезно с точки зрения отладки кода и возникшей проблемы. Рассмотрим обработку исключений на примере классической задачи превращения строки в число. Предположим, внутри метода Main() написан следующий код: while (true) { Console.WriteLine("Введите число"); string inLine = Console.ReadLine(); if (inLine == "q") { break; } int i = Convert.ToInt32(inLine); Console.WriteLine("Вы ввели {0}", i); }
В данном случае самый приемлемый подход – применение механизма исключительных ситуаций. Самый простой способ «отловить» проблемный код – заключить его в блок try: try { int i = Convert.ToInt32(inLine); Console.WriteLine("Вы ввели {0}", i); } catch (Exception fe) { Console.WriteLine(fe.Message); } Строка, которая может привести к ошибке (в данном случае к ошибке конвертирования), заключена в фигурные скобки try. Если внутри блока try произойдет ошибка, то управление будет передано в блок catch. Блоков catch может быть несколько, например: try { int i = Convert.ToInt32(inLine); Console.WriteLine("Вы ввели {0}", i); } catch (FormatException) { Console.WriteLine("Вы ввели некорректное число {0}", inLine); } catch (Exception e) { Console.WriteLine(e.Message); } После ключевого слова catch в скобках указывается имя класса исключительной ситуации, который необходимо «отловить». В первом случае catch будет обрабатывать события класса FormatException, т. е. связанные с некорректным форматом данных. Во втором блоке catch стоит класс Exception, который является базовым для всех, следовательно, он отловит любое исключение, которое не было отловлено в предыдущих блоках. В данном примере в этом блоке выводится свойство Message, где находится описание ошибки. В блоки try нужно стараться включать только действительно необходимый код. Пример неудачного оформления блока: while (true) { try { Console.WriteLine("Введите число"); string inLine = Console.ReadLine(); if (inLine == "q") { break; } int i = Convert.ToInt32(inLine); Console.WriteLine("Вы ввели {0}", i); } catch (Exception e) { } } Код в этом примере «плохой», потому что здесь в блок try заключено все содержимое цикла. В блоке catch ловятся все события благодаря использованию класса Exception, и ничего не написано, нет никакой реакции на исключительную ситуацию. Такой подход является попыткой заглушить исключительную ситуацию без попытки локализовать проблему. Исключительные ситуации создаются не только системой. В C# предусмотрена возможность самостоятельного создания исключительной ситуации, и для этого используется ключевое слово throw. Допустим, необходимо, чтобы вводимое число было не более 10. С помощью исключительной ситуации проверку можно сделать так: if (index > 10) { throw new Exception("Вы ввели слишком большое значение"); } Ключевое слово throw генерирует исключение, объект которого мы создаем после указания этого слова. В данном простейшем примере создаётся экземпляр базового класса Exception. В качестве параметра конструктору класса передаётся описание ошибки, которое попадет в свойство Message созданного объекта исключительной ситуации. В .NET существует иерархия классов исключительных ситуаций. Основные ветки: ● SystemException – исключительные ситуации этого класса и его подклассов генерируются общеязыковой средой выполнения CLR и являются исключениями системного уровня. Такие ошибки считаются неустранимыми; ● ApplicationException – ошибки приложения. Если программист планирует создавать свои классы исключительных ситуаций, рекомендуется делать их потомками ApplicationException. Создавать собственные классы исключительных ситуаций необходимо в тех случаях, когда объект, который создается при ошибке, должен содержать какие-то пользовательские данные. Быстрый способ узнать, какие классы исключений может сгенерировать метод – поставить курсор ввода на нужный метод и нажать комбинацию клавиш <Ctrl>+<K>, <I> или просто навести на метод указатель мыши. Должно появиться небольшое окно с кратким описанием метода и со списком возможных исключительных ситуаций во время вызова метода. Пример такого окна приведён ниже:
Ещё один достаточно важный блок, используемый при обработке исключений – finally. Если программный код внутри блока catch выполняется только при ошибке, то finally отработается вне зависимости от того, произошла исключительная ситуация или нет. Его можно использовать совместно с блоком catch: try { // код } catch { // произошла ошибка в коде } finally { // код выполнится вне зависимости от наличия исключения } Этот блок удобно использовать при работе с какими-то выделяемыми ресурсами, например, файлами: try { ОткрытьФайл; Прочитать данные из файла; Обработать данные; } catch { Сообщить пользователю об ошибке при работе с файлом; } finally { if (файл открыт) Закрыть файл; } В блоке try заключён метод открытия файла, который может сгенерировать исключение. Так как вызов закрытия файла написан в блоке finally, который выполняется вне зависимости от наличия исключения, то этим гарантируется, что файл будет закрыт в любом случае ‒ корректно отработали с ним или нет. |
|||||
Последнее изменение этой страницы: 2018-05-10; просмотров: 225. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |