Главная страница
Навигация по странице:

  • 2.18.1 Класс Exception и стандартные исключения

  • 2.18.2 Блок try...catch

  • 2.18.3 Блок try...finally

  • 2.18.4 Блок try...catch...finally

  • 2.18.5 Оператор throw

  • Конспект лекций (C#)-unlocked. 1 Основные сведения о C# Особенности языка


    Скачать 1.97 Mb.
    Название1 Основные сведения о C# Особенности языка
    Дата15.01.2019
    Размер1.97 Mb.
    Формат файлаpdf
    Имя файлаКонспект лекций (C#)-unlocked.pdf
    ТипДокументы
    #63730
    страница5 из 13
    1   2   3   4   5   6   7   8   9   ...   13
    Пример: перечисление дней недели: enum DayOfWeek
    {
    Monday,
    Tuesday=5,
    Wednesday,
    Thursday,
    Friday=7,
    Saturday,
    Sunday
    }
    DayOfWeek d; d = DayOfWeek.Monday;
    Если элементам перечисления не назначены значения, то они нумеруются по- следовательно с нуля. Если какому-нибудь элементу назначено значение, то следу- ющий элемент без значения, расположенный сразу за ним, получает значение на 1 больше. Например в приведённом выше примере значения элементов перечисления будут следующими:
    Monday=0, Tuesday=5, Wednesday=6, Thursday=7, Friday=7, Saturday=8,
    Sunday=9
    Значения, назначаемые элементам перечисления, могут быть абсолютно лю- быми, например: enum WorldWar2Years
    {
    Start=1939,
    End=1945,
    Stalingrad=1942,
    Kursk=1943
    }
    2.18
    Обработка исключений
    Исключительная ситуация (исключение) – это возникновение в программе ошибочной ситуации того или иного рода, например, деление на ноль, попытка пре- образовать в число строку и т.д.
    В случае возникновения исключения программа прекращает выполнение те- кущего блока и выдаёт сообщение об обнаруженной ошибке. Однако перехват и об-

    40 работка возникающих ошибок позволяет улучшить контроль за выполнением про- граммы.
    В языке С# исключения представлены в виде классов. Все классы исключений являются производными от встроенного в С# класса
    Exception
    , являющегося ча- стью пространства имён
    System
    Обработка исключительных ситуаций в С# организуется с помощью четырёх ключевых слов: try
    , catch
    , throw и finally
    . Они образуют взаимосвязанную подсистему, в которой применение одного из ключевых слов подразумевает приме- нение другого.
    2.18.1
    Класс Exception и стандартные исключения
    Класс
    Exception
    , являясь родителем всех классов исключений, предоставля- ет им единые свойства и методы, некоторыми из которых являются:

    Message
    – текст, описывающий исключение;

    StackTrace
    – позволяет получить стек вызовов для определения места возник- новения исключения;

    GetType()
    – возвращает тип исключения. В сочетании с методом
    ToString()
    имеется возможность получить строковое представление типа исключения.
    Некоторые стандартные исключения приведены в таблице 2.5.
    Таблица 2.5 – Некоторые стандартные исключения
    Наименование
    Причина возникновения исключения
    AccessViolationException попытка чтения или записи в защищённую об- ласть памяти
    ArithmeticException ошибки в арифметических действий, а также операциях приведения к типу и преобразования
    DivideByZeroException попытка деления на ноль. Для вещественных чи- сел не возникает, т.к. там используются значения
    ± бесконечность или нечисловое значение
    OverflowException переполнение при выполнении арифметических операций, операций приведения типов и преоб- разования
    FormatException ошибка при преобразовании из одного типа дан- ных в другой, например, при преобразовании из строки в число методами класса
    Convert
    IndexOutOfRangeException попытка обращения к элементу массива с индек- сом, который находится вне границ массива
    InvalidCastException недопустимое приведение или явное преобразо- вание типов
    IOException ошибки ввода-вывода
    DirectoryNotFoundException невозможно найти часть файла или каталога

    41
    Продолжение таблицы 2.5
    Наименование
    Причина возникновения исключения
    DriveNotFoundException попытка доступа к недоступному диску или данным совместного использования
    EndOfStreamException попытка выполнить чтение за пределами потока
    FileNotFoundException попытка доступа к файлу, не существующему на дис- ке
    PathTooLongException путь или имя файла превышает максимальную длину, определённую системой
    NullReferenceException попытка использовать пустую ссылку, т.е. ссылку, ко- торая не указывает ни на один из объектов
    Иерархия некоторых классов исключений имеет вид:
    Exception
    SystemException
    AccessViolationException
    ArithmeticException
    DivideByZeroException
    OverflowException
    FormatException
    IndexOutOfRangeException
    InvalidCastException
    IOException
    DirectoryNotFoundException
    DriveNotFoundException
    EndOfStreamException
    FileNotFoundException
    PathTooLongException
    NullReferenceException
    Знание иерархии классов важно для правильной обработки возникающих ис- ключений.
    2.18.2
    Блок try...catch
    Основу обработки исключительных ситуаций в С# составляет пара ключевых слов try и catch
    , формальное использование которых имеет вид: try
    {
    <блок кода, проверяемый на ошибки>
    } catch (<тип исключения 1> [<переменная исключения 1>])
    {
    <обработка исключения типа 1>
    }
    [catch (<тип исключения 2> [<переменная исключения 2>])

    42
    {
    <обработка исключения типа 2>
    } ...]
    Принцип работы блока try...catch следующий. При возникновении ошиб- ки в блоке
    <блок кода, проверяемый на ошибки>
    дальнейшее выполнение данного блока прекращается и управление передаются тому блоку catch
    (т.е. вы- полняется блок
    <обработка исключения типа N>
    ), у которого
    <тип исключения N>
    совпадает с типом возникшей ошибки. Если при выполнении блока
    <обработка исключения типа N> требуется доступ к параметрам исключения, то в блоке catch может быть описана переменная
    <переменная исключения N>
    Если в блоке
    <блок кода, проверяемый на ошибки> не возникло оши- бок, то все блоки catch пропускаются.
    При использовании нескольких блоков catch все типы исключений, которые они обрабатывают, должны быть разными. При этом, если между двумя типами ис- ключений есть связь «родитель–потомок», то сначала должна быть описана обра- ботка «исключения–потомка».
    Пример: найти результат целочисленного деления числа
    1000
    на число a
    , ко- торое пользователь вводит в компоненте
    A_TB
    класса
    TextBox
    . Результат вывести в компонент
    R_TB
    класса
    TextBox try
    { int a = Convert.ToInt32(A_TB.Text);
    R_TB.Text = String.Format(
    "Результат выражения 1000/{0} равен {1}", a, 1000/a);
    } catch (FormatException)
    {
    R_TB.Text = "Ошибка: число А должно быть целым";
    } catch (DivideByZeroException)
    {
    R_TB.Text = "Ошибка: деление на 0";
    }
    Блоки try...catch могут быть вложенными. При этом, если исключение возникает во внутреннем блоке, и там не обрабатывается, то оно передаётся во внешний блок, где может быть обработано
    1
    Пример: найти результат целочисленного деления числа
    1000
    на число a
    , ко- торое пользователь вводит в компоненте
    A_TB
    класса
    TextBox
    . Результат вывести в компонент
    R_TB
    класса
    TextBox
    . Если число введено неправильно, то считать его значение равным 1.
    1
    В общем случае все блоки try...catch можно рассматривать как вложенные, т.к. все они находятся в блоке обработки исключений программы, вставляемом компилятором автоматически.

    43 try
    { int a; try
    { a = Convert.ToInt32(A_TB.Text);
    } catch (FormatException)
    { a = 1;
    }
    R_TB.Text = String.Format(
    "Результат выражения 1000/{0} равен {1}", a, 1000/a);
    } catch (DivideByZeroException)
    {
    R_TB.Text = "Ошибка: деление на 0";
    }
    В блоке catch может не указываться тип исключения. В этом случае такой блок располагается самым последним и обрабатывает все типы исключений, не об- работанные до него.
    2.18.3
    Блок try...finally
    Блок try...finally применяется для создания фрагмента кода, который должен выполниться даже в том случае возникновения исключения. Формальная структура данного блока имеет вид: try
    {
    <блок кода, проверяемый на ошибки>
    } finally
    {
    <обязательно выполняемый фрагмент кода>
    }
    Алгоритм работы блока try...finally следующий. При возникновении ошибки в блоке
    <блок кода, проверяемый на ошибки>
    дальнейшее выполне- ние данного блока прекращается и управление передаются блоку finally
    (т.е. вы- полняется блок
    <обязательно выполняемый фрагмент кода>
    ).
    Если в блоке
    <блок кода, проверяемый на ошибки> не возникло оши- бок, то управление передаётся блоку finally
    Следует отметить, что возникающая ошибка останется необработанной, т.е. будет выдано стандартное сообщение о необработанной ошибке.
    Пример: найти результат целочисленного деления числа
    1000
    на число a
    , ко- торое пользователь вводит в компоненте
    A_TB
    класса
    TextBox
    . Результат вывести в

    44 компонент
    R_TB
    класса
    TextBox
    . Если число введено неправильно или равно 0, то считать его значение равным 1. int a=1; try
    { a = Convert.ToInt32(A_TB.Text); if (a==0) a = 1;
    } finally
    {
    R_TB.Text = String.Format(
    "Результат выражения 1000/{0} равен {1}", a, 1000/a);
    }
    2.18.4
    Блок try...catch...finally
    Чтобы не оставалось необработанных ошибок при использовании блока try...finally
    , он, как правило, применяется в сочетании с блоком try...catch
    , путём добавления после него блока finally
    . При этом, в некоторых случаях блоки catch могут остаться пустыми.
    Пример: найти результат целочисленного деления числа
    1000
    на число a
    , ко- торое пользователь вводит в компоненте
    A_TB
    класса
    TextBox
    . Результат вывести в компонент
    R_TB
    класса
    TextBox
    . Если число введено неправильно или равно 0, то считать его значение равным 1. int a=1; try
    { a = Convert.ToInt32(A_TB.Text); if (a==0) a = 1;
    } catch (Exception)
    {
    } finally
    {
    R_TB.Text = String.Format(
    "Результат выражения 1000/{0} равен {1}", a, 1000/a);
    }

    45
    2.18.5
    Оператор throw
    В приведённых выше примерах исключения генерировались программой ав- томатически. Однако в некоторых случаях бывает полезным сгенерировать исклю- чение вручную. Формальное описание оператора генерации исключения имеет вид: throw <объект класса исключения>;
    Во многих случаях генерация исключения объединяется с созданием объекта, например: throw new Exception("Неправильно введены данные");
    Пример: найти результат целочисленного деления числа
    1000
    на число a
    , ко- торое пользователь вводит в компоненте
    A_TB
    класса
    TextBox
    . Число a
    должно быть в диапазоне -100...100. Результат вывести в компонент
    R_TB
    класса
    TextBox try
    { int a = Convert.ToInt32(A_TB.Text); if (a < -100 || a > 100) throw new Exception("Число А должно быть в диапазоне -100...100");
    R_TB.Text = String.Format(
    "Результат выражения 1000/{0} равен {1}", a, 1000/a);
    } catch (FormatException)
    {
    R_TB.Text = "Ошибка: число А должно быть целым";
    } catch (DivideByZeroException)
    {
    R_TB.Text = "Ошибка: деление на 0";
    } catch (Exception E)
    {
    R_TB.Text = E.Message;
    }
    С помощью оператора throw можно повторно сгенерировать исключение по- сле его обработки в блоке catch для того, чтобы оно также было обработано во внешнем блоке catch
    . Для этого во внутреннем блоке catch последним операто- ром указывается оператор throw без параметров.
    Например, предыдущий пример может быть записан следующим образом: try
    { int a=0; try
    { a = Convert.ToInt32(A_TB.Text);

    46 if (a < -100 || a > 100) throw new Exception(
    "Число А должно быть в диапазоне -100...100");
    } catch (FormatException)
    {
    MessageBox.Show("Ошибка: число А должно быть целым"); throw;
    } catch (Exception E)
    {
    MessageBox.Show(E.Message); throw;
    }
    R_TB.Text = String.Format(
    "Результат выражения 1000/{0} равен {1}", a, 1000/a);
    } catch (Exception)
    {
    R_TB.Text = "Результат не найден из-за неправильного ввода числа А";
    }

    47
    3
    Классы. Основные понятия
    Класс представляет собой тип, содержащий данные, а также методы, позволя- ющие оперировать этими данными. Все элементы, входящие в класс будем называть
    членами класса.
    Для каждого объекта класса создаётся своя копия членов-данных, в то время, как члены-методы являются общими для всех объектов.
    3.1
    Общая схема
    Общая схема определения класса имеет вид:
    [<доступ>] class <идентификатор класса> [: <идентификатор класса- родителя>]
    {
    <члены класса>
    } где:

    <доступ>
    – спецификатор доступа и/или модификаторы;

    <идентификатор класса>
    – идентификатор создаваемого класса;

    <идентификатор класса-родителя>
    – идентификатор класса, от которого наследует свойства и поведение создаваемый класс;

    <члены класса>
    – поля, методы, свойства и другие структурные единицы клас- са.
    3.2
    Спецификаторы доступа
    При объявлении класса или члена класса могут указываться ключевые слова, определяющие тип доступа к ним (спецификаторы доступа):

    public
    – доступен без каких-либо ограничений;

    protected
    – доступен внутри тела класса, а также для потомков класса;

    internal
    – доступен только внутри файлов одной и той же сборки. Внутренний доступ чаще всего используется в разработке на основе компонентов, так как он позволяет группе компонентов взаимодействовать в закрытой форме, не открывая доступ остальной части кода приложения;

    protected internal
    – комбинация доступа protected и internal
    ;

    private
    – доступен только внутри тела класса, в котором он объявлен.
    По умолчанию (т.е. если нет явного указания), члены класса имеют доступ private
    , а классы – internal
    ;
    Спецификаторы доступа protected и private не могут применяться к клас- сам верхнего уровня, т.е. классам, не входящим в состав других классов.

    48
    Поля класса объявляются, как правило, с помощью спецификаторов доступа protected и private
    , т.к. доступ к данным класса извне реализуется с помощью свойств, методов или индексаторов. Использование для доступа к полям специфика- тора public снижает надёжность программы
    1
    3.3
    Поля
    Поле по своей сути представляет обычную переменную некоторого типа, для которой задан спецификатор доступа. Формальная схема описания полей имеет вид:
    [<доступ>] <тип> <идентификатор 1>[=<значение идентификатора 1>][,
    <идентификатор2>[=<значение идентификатора 2>] ...];
    Примеры:
    private double d; protected int a, b=10;
    Начальное значение поля может быть задано через конструктор класса, при этом порядок задания начальных значений следующий:

    присвоение полю значения по умолчанию для его типа;

    присвоение значения инициализации, заданного при объявлении поля;

    присвоение значения, указанного в конструкторе.
    3.4
    Создание объекта и доступ к его членам
    В качестве начального примера работы с классами возьмём класс, описанный следующим образом: class Figure
    { public string sType; // строковое представление типа фигуры public int posX, posY; // координаты фигуры
    }
    Объявление переменной, которая может ссылаться на экземпляр некоторого класса (объект) выполняется обычным для переменных способом, например:
    Figure firstFigure;
    Классы являются ссылочным типом, поэтому перед использованием перемен- ных данного типа требуется либо задание ссылки на существующий объект, либо созданием объекта путём использования оператора new совместно с вызовом специ- ального метода – конструктора класса, Простейший конструктор (конструктор по
    1
    В приводимых в конспекте примерах для уменьшения объёма кода и простоты изложения использование полей со спецификатором доступа public будем считать допустимым.

    49 умолчанию) вызывается путём указания имени класса с круглыми скобками после него, например: firstFigure = new Figure();
    Часто операции по объявлению переменной и созданию объекта объединяют- ся, например:
    Figure firstFigure = new Figure();
    Для обращения к члену класса используется оператор доступа «.», разделяю- щий идентификатор объекта и идентификатор члена, к которому осуществляется доступ. Например, задать строковое представление типа фигуры можно следующим образом: firstFigure.sType = "Квадрат";
    3.5
    Методы
    Хотя классы, содержащие только данные, вполне допустимы, у большинства классов должны быть также методы. Методы представляют собой подпрограммы, которые манипулируют данными, определёнными в классе, а во многих случаях они предоставляют доступ к этим данным. Как правило, другие части программы взаи- модействуют с классом посредством его методов.
    Формальная схема описания метода имеет вид:
    [<доступ>] <возвращаемый тип> <метод>([<список параметров>])
    {
    <тело метода>
    } где:

    <доступ>
    – спецификатор доступа и/или модификаторы;

    <возвращаемый тип>
    – тип данных, возвращаемых методом. Если метод не воз- вращает данных, то указывается ключевое слово
    void
    ;

    <метод>
    – идентификатор создаваемого метода;

    <список параметров>
    – список параметров, передаваемых в метод или возвра- щаемых им;

    <тело метода>
    – код, определяющий набор действий, выполняемых методом.
    В списке параметров, параметры разделяются запятыми. Описание каждого параметра имеет вид:
    [<модификатор параметра>] <тип> <идентификатор параметра> где:

    <модификатор параметра>
    – ключевое слово, определяющее способы работы с параметром;

    50

    <тип>
    – тип данных, к которому принадлежат параметр;

    <идентификатор параметра>
    – идентификатор, под которым параметр будет известен внутри метода.
    Пример: дополним класс
    Figure методами, позволяющими оперировать с полем sType
    (а также заблокируем прямой доступ к полю sType путём задания для него спецификатора доступа private и укажем его начальное значение). class Figure
    { private string sType="Не задан"; public int posX, posY; public string GetSType()
    { return sType;
    } public void SetSType(string n_sType)
    { if (n_sType.Trim() != "") sType = n_sType.Trim();
    }
    }
    Каждый метод, у которого возвращаемый тип отличен от void
    , должен со- держать оператор return
    (или несколько таких операторов для каждой ветви раз- ветвляющегося кода), с указанием значения, которое возвращается методом. Ука- занное значение должно быть совместимо с возвращаемым типом. Например, в ме- тоде
    GetSType()
    возвращаемым типом является string
    , поэтому указание в каче- стве возвращаемого значения текущего значения поля sType вполне допустимо.
    Вызов оператора return приводит к
    1   2   3   4   5   6   7   8   9   ...   13


    написать администратору сайта