Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Обработка исключительных ситуаций

Исключительная ситуация ( исключение) происходит во время выполнения. Используя подсистему обработки исключительных ситуаций в С#, можно обрабатывать структурированным и контролируемым образом ошибки, возникающие при выполнении программы.

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

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

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

 

Класс System.Exception

В С# исключения представлены в виде классов. Все классы исключений должны быть производными от встроенного в С# класса Exception, являющегося частью пространства имен System. Следовательно, все исключения являются подклассами класса Exception.

К числу самых важных подклассов Exception относится класс SystemException. Именно от этого класса являются производными все исключения, генерируемые исполняющей системой С# (т.е. системой CLR).

В среде.NET Framework определено несколько встроенных исключений, являющихся производными от класса SystemException. Например, при попытке выполнить деление на нуль генерируется исключение DivideByZeroException.

В С# можно создавать собственные классы исключений, производные от класса Exception.

 

Основы обработки исключительных ситуаций

 

Обработка исключительных ситуаций в С# организуется с помощью четырех ключевых слов: try, catch, throw и finally.

Операторы программы, которые требуется контролировать на появление исключений, заключаются в блок try. Если внутри блока try возникает исключительная ситуация, генерируется исключение. Это исключение может быть перехвачено и обработано каким-нибудь рациональным способом в коде программы с помощью оператора, обозначаемого ключевым словом catch. Исключения, возникающие на уровне системы, генерируются исполняющей системой автоматически. А для генерирования исключений вручную служит ключевое слово throw. Любой код, который должен быть непременно выполнен после выхода из блока try, помещается в блок finally.

 

Основу обработки исключительных ситуаций в С# составляет пара ключевых слов try и catch. Эти ключевые слова действуют совместно и не могут быть использованы порознь. Общая форма определения блоков try/catch для обработки исключительных ситуаций:

try {

// Блок кода, проверяемый на наличие ошибок.

}

catch {ExcepTypel exOb) {

// Обработчик исключения типа ExcepTypel.

}

catch {ExcepType2 exOb) {

// Обработчик исключения типа ЕхсерТуре2.

}

где ЕхсерТуре — это тип возникающей исключительной ситуации. Когда исключение генерируется оператором try, оно перехватывается составляющим ему пару оператором catch, который затем обрабатывает это исключение. В зависимости от типа исключения выполняется и соответствующий оператор catch. Так, если типы генерируемого исключения и того, что указывается в операторе catch, совпадают, то выполняется именно этот оператор, а все остальные пропускаются. Когда исключение перехватывается, переменная исключения exOb получает свое значение.

Указывать переменную exOb необязательно, если обработчику исключений не требуется доступ к объекту исключения, что бывает довольно часто. Для обработки исключения достаточно и его типа.

Если исключение не генерируется, то блок оператора try завершается как обычно, и все его операторы catch пропускаются. Выполнение программы возобновляется с первого оператора, следующего после завершающего оператора catch. Таким образом, оператор catch выполняется лишь в том случае, если генерируется исключение.

 

Пример, демонстрирующий отслеживание и перехватывание исключения.

Попытка индексировать массив за его границами приводит к ошибке. Когда возникает подобная ошибка, система CLR генерирует исключение IndexOutOf RangeException, которое определено как стандартное для среды.NET Framework. В программе такое исключение генерируется намеренно и затем перехватывается.

 

// Продемонстрировать обработку исключительной ситуации.

using System;

class ExcDemol {

static void Main() {

int[] nums = new int[4];

try {

Console.WriteLine("До генерирования исключения.");

// Сгенерировать исключение в связи с выходом индекса за границы массива,

for (int i=0; i < 10; i++) {

nums[i] = i;

Console.WriteLine("nums[{0}]: {1}", i, nums[i]);

}

Console.WriteLine("He подлежит выводу");

}

catch (IndexOutOfRangeException) {

// Перехватить исключение.

Console.WriteLine("Индекс вышел за границы массива!");

}

Console.WriteLine("После блока перехвата исключения.");

}

}

При выполнении этой программы получается следующий результат.

До генерирования исключения.

nums[0]: 0

nums[1]: 1

nums[2]: 2

nums[3]: 3

Индекс вышел за границы массива!

После блока перехвата исключения.

 

В примере массив nums типа int состоит из четырех элементов. Но в цикле for предпринимается попытка проиндексировать этот массив от 0 до 9, что и приводит к появлению исключения IndexOutOfRangeException, когда происходит обращение к элементу массива по индексу 4.

Во-первых, код, который требуется контролировать на наличие ошибок, содержится в блоке try. Во-вторых, когда возникает исключительная ситуация (в данном случае — при попытке проиндексировать массив nums за его границами в цикле for), в блоке try генерируется исключение, которое затем перехватывается в блоке catch. В этот момент выполнение кода в блоке try завершается и управление передается блоку catch. Это означает, что оператор catch не вызывается специально, а выполнение кода переходит к нему автоматически. Следовательно, оператор, содержащий метод WriteLine() и следующий непосредственно за циклом for, где происходит выход индекса за границы массива, вообще не выполняется. А в задачу обработчика исключений входит исправление ошибки, приведшей к исключительной ситуации, чтобы продолжить выполнение программы в нормальном режиме.

В операторе catch указан только тип исключения (в данном случае — IndexOutOfRangeException), а переменная исключения отсутствует.

Переменную исключения требуется указывать лишь в том случае, если требуется доступ к объекту исключения.

В ряде случаев значение объекта исключения может быть использовано обработчиком исключений для получения дополнительной информации о самой ошибке, но зачастую для обработки исключительной ситуации достаточно просто знать, что она произошла. Поэтому переменная исключения нередко отсутствует в обработчиках исключений, как в рассматриваемом здесь примере.

 

Если стандартное исключение не перехватывается в программе, то оно будет перехвачено исполняющей системой, которая выдаст сообщение об ошибке и прервет выполнение программы.

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

 

Пример. Программа, в которой элементы одного массива делятся на элементы другого. Если при этом происходит деление на нуль, то генерируется исключение DivideByZeroException. Обработка подобной исключительной ситуации заключается в том, что программа уведомляет об ошибке и затем продолжает свое выполнение. Таким образом, попытка деления на нуль не приведет к аварийному завершению программы из-за ошибки при ее выполнении. Вместо этого ошибка обрабатывается "изящно", не прерывая выполнение программы.

 

// Изящно обработать исключительную ситуацию и продолжить выполнение программы.

using System;

class ExcDemo3 {

static void Main() {

int[] numer = { 4, 8, 16, 32, 64, 128 };

int[] denom = { 2, 0, 4, 4, 0, 8 };

for(int i=0; i < numer.Length; i++) {

try { Console.WriteLine(numer[i] + " / " + denom[i] + " равно " +

numer[i]/denom[i]);

}

catch (DivideByZeroException) {

// Перехватить исключение.

Console.WriteLine("Делить на нуль нельзя!");

}

}

}

}

Результат выполнения этой программы.

4/2 равно 2

Делить на нуль нельзя!

16/4 равно 4

32/4 равно 8

Делить на нуль нельзя!

128 / 8 равно 16

Как только исключение обработано, оно удаляется из системы.

Поэтому в программе проверка ошибок в блоке try начинается снова на каждом шаге цикла for, при условии, что все предыдущие исключительные ситуации были обработаны. Это позволяет обрабатывать в программе повторяющиеся ошибки.

С одним оператором try можно связать несколько операторов catch. Но все операторы catch должны перехватывать исключения разного типа.

 

Пример перехвата ошибки выхода за границы массива и деления на нуль.

// Использовать несколько операторов catch.

using System;

class ExcDemo4 {

static void Main() {

// Здесь массив numer длиннее массива denom.

int[] numer = {4, 8, 16, 32, 64, 128, 256, 512 };

int[] denom ={2, 0, 4, 4, 0, 8};

for(int i=0; i < numer.Length; i++) {

try {

Console.WriteLine(numer[i] + " / " + denom[i] + " равно " +

numer[i]/denom[i]);

}

catch (DivideByZeroException) {

Console.WriteLine("Делить на нуль нельзя!");

}

catch (IndexOutOfRangeException) {

Console.WriteLine("Подходящий элемент не найден.");

}

}

}

}

Вот к какому результату приводит выполнение этой программы.

4/2 равно 2

Делить на нуль нельзя!

16/4 равно 4

32/4 равно 8

Делить на нуль нельзя!

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

 

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

catch {

// обработка исключений

}

С помощью такой формы создается "универсальный" обработчик всех исключений, перехватываемых в программе. Блок "универсального" перехвата должен располагаться последним по порядку среди всех блоков catch.

 

Пример. Перехватывает и обрабатывает оба исключения,

IndexOutOfRangeException и DivideByZeroException, генерируемых.в программе.

// Использовать "универсальный" обработчик исключений.

using System;

class ExcDemo5 {

static void Main() {

// Здесь массив numer длиннее массива denom.

int[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };

int[] denom ={2,0,4,4,0,8};

for(int i=0; i < numer.Length; i++) {

try {

Console.WriteLine(numer[i] + " / " + denom[i] + " равно " +

numer[i]/denom[i]);

}

catch { // "Универсальный" перехват.

Console.WriteLine("Возникла некоторая исключительная ситуация.");

}

}

}

}

При выполнении этой программы получается следующий результат.

4/2 равно 2

Возникла некоторая исключительная ситуация.

16/4 равно 4

32/4 равно 8

Возникла некоторая исключительная ситуация.

128 / 8 равно 16

Возникла некоторая исключительная ситуация.

Возникла'некоторая исключительная ситуация.

 

Исключение может быть сгенерировано и вручную с помощью оператора throw. Ниже приведена общая форма такого генерирования:

throw exceptOb;

где в качестве exceptOb должен быть обозначен объект класса исключений, производного от класса Exception.

 

Пример программы, в которой демонстрируется применение оператора throw для генерирования исключения DivideByZeroException.

// Сгенерировать исключение вручную.

using System;

class ThrowDemo {

static void Main() {

try {

Console.WriteLine("До генерирования исключения.");

throw new DivideByZeroException ();

}

catch (DivideByZeroException) {

Console.WriteLine("Исключение перехвачено.");

}

Console.WriteLine("После пары операторов try/catch.");

}

}

Вот к какому результату приводит выполнение этой программы.

До генерирования исключения.

Исключение перехвачено.

После пары операторов try/catch.

Исключение DivideByZeroException было сгенерировано с использованием ключевого слова new в операторе throw. В данном случае генерируется конкретный объект, а следовательно, он должен быть создан перед генерированием исключения. Это означает, что сгенерировать исключение только по его типу нельзя. В данном примере для создания объекта DivideByZeroException был автоматически вызван конструктор, используемый по умолчанию, хотя для генерирования исключений доступны и другие конструкторы.

 

Иногда требуется определить кодовый блок, который будет выполняться после выхода из блока try/catch. В частности, исключительная ситуация может возникнуть в связи с ошибкой, приводящей к преждевременному возврату из текущего метода. Но в этом методе мог быть открыт файл, который нужно закрыть, или же установлено сетевое соединение, требующее разрывания. Подобные ситуации нередки в программировании, и поэтому для их разрешения в С# предусмотрен удобный способ: воспользоваться блоком fina11у.

Для того чтобы указать кодовый блок, который должен выполняться после блока try/catch, достаточно вставить блок finally в конце последовательности операторов try/catch. Ниже приведена общая форма совместного использования блоков try/ catch и finally.

try {

// Блок кода, предназначенный для обработки ошибок.

}

catch (ExcepTypel exOb) {

// Обработчик исключения типа ExcepTypel.

}

catch (ExcepType2 ехОЬ) {

// Обработчик исключения типа ЕхсерТуре2.

}

finally {

// Код завершения обработки исключений.

}

Блок finally будет выполняться всякий раз, когда происходит выход из блока try/catch, независимо от причин, которые к этому привели. Это означает, что если блок try завершается нормально или по причине исключения, то последним выполняется код, определяемый в блоке finally. Блок finally выполняется и в том случае, если любой код в блоке try или в связанных с ним блоках catch приводит к возврату из метода.

 

Пример применения блока finally.

// Использовать блок finally.

using System;

class UseFinally {

public static void GenException(int what) {

int t;

int[] nums = new int [2];

Console.WriteLine("Получить " + what);

try {

switch(what) {

case 0:

t = 10 / what; // сгенерировать ошибку из-за деления на нуль

break;

case l:

nums[4] = 4; // сгенерировать ошибку индексирования массива

break;

case 2:

return; // возврат из блока try

}

}

catch (DivideByZeroException) {

Console.WriteLine("Делить на нуль нельзя!");

return; // возврат из блока catch

}

catch (IndexOutOfRangeException) {

Console.WriteLine("Совпадающий элемент не найден.");

}

finally {

Console.WriteLine("После выхода из блока try.");

}

}

}

class FinallyDemo {

static void Main() {

for(int i=0; i < 3; i++) {

UseFinally.GenException(i);

Console.WriteLine();

}

}

}

Вот к какому результату приводит выполнение этой программы.

Получить О

Делить на нуль нельзя

После выхода из блока try.

Получить 1

Совпадающий элемент не найден.

После выхода из блока try.

Получить 2

После выхода из блока try.

 

Блок finally выполняется независимо от причины выхода из блока try.

Блок finally следует после блока try, и формально блоки catch для этого не требуются. Следовательно, блок finally можно ввести непосредственно после блока try, опустив блоки catch. В этом случае блок finally начнет выполняться сразу же после выхода из блока try, но исключения обрабатываться не будут.

 

В классе Exception определяется ряд свойств. К числу самых интересных

относятся три свойства: Message, StackTrace и TargetSite. Все эти свойства доступны

только для чтения. Свойство Message содержит символьную строку, описывающую

характер ошибки; свойство StackTrace — строку с вызовами стека, приведшими к

исключительной ситуации, а свойство TargetSite получает объект, обозначающий

метод, сгенерировавший исключение.

Кроме того, в классе Exception определяется ряд методов. Чаще всего приходится

пользоваться методом ToString (), возвращающим символьную строку с описанием

исключения. Этот метод автоматически вызывается, например, при отображении

исключения с помощью метода WriteLine().

 

// Использовать члены класса Exception.

using System;

class ExcTest {

public static void GenException() {

int[] nums = new int[4];

Console.WriteLine("До генерирования исключения.");

// Сгенерировать исключение в связи с выходом за границы массива.

for(int i=0; i < 10; i++) {

nums[i] = i;

Console.WriteLine("nums[{0}]: {1}", i, nums[i]);

}

Console.WriteLine("He подлежит выводу");

}

}

class UseExcept {

static void Main() {

try {

ExcTest.GenException();

}

catch (IndexOutOfRangeException exc) {

Console.WriteLine("Стандартное сообщение таково: ¦");

Console.WriteLine(exc); // вызвать метод ToStringO

Console.WriteLine("Свойство StackTrace: " + exc.StackTrace);

Console.WriteLine("Свойство Message: " + exc.Message);

Console.WriteLine("Свойство TargetSite: " + exc.TargetSite);

}

Console.WriteLine("После блока перехвата исключения.");

}

}

При выполнении этой программы получается следующий результат.

До генерирования исключения.

nums[0]: 0

nums[1]: 1

nums[2]: 2

nums[3]: 3

Стандартное сообщение таково: System.IndexOutOfRangeException: Индекс находился

вне границ массива.

в ExcTest.genException() в <имя_файла>:строка 15

в UseExcept.Main()в <имя_файла>:строка 2 9

Свойство StackTrace: в ExcTest.genException()в <имя_файла>:строка 15

в UseExcept.Main()в <имя_файла>:строка 29

Свойство Message: Индекс находился вне границ массива.

Свойство TargetSite: Void genException ()

После блока перехвата исключения.

 

Допускается использовать исключения, определяемые пользователем, т.е. тем, кто

программирует на С#. Такие специальные исключения можно использовать для обработки ошибок в собственном коде. Для их создания достаточно определить класс, производный от класса Exception. Создаваемые пользователем классы будут автоматически получать свойства и

методы, определенные в классе Exception и доступные для них. Когда создается собственный класс исключений, то, желательно, чтобы в нем поддерживались все конструкторы, определенные в классе Exception. В простых специальных классах исключений этого нетрудно добиться, поскольку для этого достаточно передать подходящие аргументы соответствующему конструктору класса Exception, используя ключевое слово base. Но формально нужно предоставить только те конструкторы, которые фактически используются в программе.

 

 


<== предыдущая | следующая ==>
Участники и условия проведения игры | Классификация трубопроводов

Date: 2015-10-21; view: 527; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.005 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию