Полное руководство. С# 4.0
Шрифт:
выводится следующий результат. RedDel имеет значение 2
Как показывает результат выполнения приведенного выше фрагмента кода, для вы вода перечислимого значения используется его имя. Но для получения этого значения требуется предварительно привести его к типу int.
Ниже приведен пример программы, демонстрирующий применение перечисле ния Apple. // Продемонстрировать применение перечисления. using System; class EnumDemo { enum Apple { Jonathan, GoldenDel, RedDel, Winesap, Cortland, McIntosh }; static void Main { string[] color = { "красный", "желтый", "красный", "красный", "красный", "красновато-зеленый" }; Apple i; // объявить переменную перечислимого типа // Использовать переменную i для циклического // обращения к членам перечисления. for(i = Apple.Jonathan; i <= Apple.McIntosh; i++) Console.WriteLine(i + " имеет значение " + (int)i); Console.WriteLine; //
Ниже приведен результат выполнения этой программы. Jonathan имеет значение 0 GoldenDel имеет значение 1 RedDel имеет значение 2 Winsap имеет значение 3 Cortland имеет значение 4 McIntosh имеет значение 5 Цвет сорта Jonathan - красный Цвет сорта GoldenDel - желтый Цвет сорта RedDel - красный Цвет сорта Winsap - красный Цвет сорта Cortland - красный Цвет сорта McIntosh - красновато-зеленый
Обратите внимание на то, как переменная типа Apple управляет циклами for. Значения символически обозначаемых констант в перечислении Apple начинаются с нуля, поэтому их можно использовать для индексирования массива, чтобы получить цвет каждого сорта яблок. Обратите также внимание на необходимость производить приведение типов, когда перечислимое значение используется для индексирования массива. Как упоминалось выше, в C# не предусмотрены неявные преобразования перечислимых типов в целочисленные и обратно, поэтому для этой цели требуется явное приведение типов.
И еще одно замечание: все перечисления неявно наследуют от класса System.Enum, который наследует от класса System.ValueType, а тот, в свою очередь, — от класса object. Инициализация перечисления
Значение одной или нескольких символически обозначаемых констант в перечис лении можно задать с помощью инициализатора. Для этого достаточно указать после символического обозначения отдельной константы знак равенства и целое значение. Каждой последующей константе присваивается значение, которое на единицу больше значения предыдущей инициализированной константы. Например, в приведенном ниже фрагменте кода константе RedDel присваивается значение 10. enum Apple { Jonathan, GoldenDel, RedDel = 10, Winesap, Cortland, McIntosh };
В итоге все константы в перечислении принимают приведенные ниже значения. Jonathan 0 GoldenDel 1 RedDel 10 Winesap 11 Cortland 12 McIntosh 13 Указание базового типа перечисления
По умолчанию в качестве базового для перечислений выбирается тип int, тем не менее перечисление может быть создано любого целочисленного типа, за исключени ем char. Для того чтобы указать другой тип, кроме int, достаточно поместить этот тип после имени перечисления, отделив его двоеточием. В качестве примера ниже за дается тип byte для перечисления Apple. enum Apple : byte { Jonathan, GoldenDel, RedDel, Winesap, Cortland, McIntosh };
Теперь константа Apple.Winesap, например, имеет количественное значение типа byte. Применение перечислений
На первый взгляд перечисления могут показаться любопытным, но не очень нуж ным элементом С#, но на самом деле это не так. Перечисления очень полезны, когда в программе требуется одна или несколько специальных символически обозначаемых констант. Допустим, что требуется написать программу для управления лентой кон вейера на фабрике. Для этой цели можно создать метод Conveyor, принимающий в качестве параметров следующие команды: "старт", "стоп", "вперед" и "назад". Вместо того чтобы передавать методу Conveyor целые значения, например, 1 — в качестве команды "старт", 2 — в качестве команды "стоп" и так далее, что чревато ошибками, можно создать перечисление, чтобы присвоить этим значениям содержательные сим волические обозначения. Ниже приведен пример применения такого подхода. // Сымитировать управление лентой конвейера. using System; class ConveyorControl { // Перечислить команды конвейера. public enum Action { Start, Stop, Forward, Reverse }; public void Conveyor(Action com) { switch(com) { case Action.Start: Console.WriteLine("Запустить конвейер."); break; case Action.Stop: Console.WriteLine("Остановить конвейер."); break; case Action.Forward: Console.WriteLine("Переместить конвейер вперед."); break; case Action.Reverse: Console.WriteLine("Переместить конвейер назад."); break; } } } class ConveyorDemo { static void Main { ConveyorControl с = new ConveyorControl; с.Conveyor(ConveyorControl.Action.Start); с.Conveyor(ConveyorControl.Action.Forward); с.Conveyor(ConveyorControl.Action.Reverse); с.Conveyor(ConveyorControl.Action.Stop); } }
Вот к какому результату приводит выполнение этого кода. Запустить конвейер. Переместить конвейер вперед. Переместить конвейер назад. Остановить конвейер.
Метод Conveyor принимает аргумент типа Action, и поэтому ему могут быть переданы только значения, определяемые в перечислении Action. Например, ниже приведена попытка передать методу Conveyor значение 22. с.Conveyor(22); // Ошибка!
Эта строка кода не будет скомпилирована, поскольку отсутствует предваритель но заданное преобразование типа int в перечислимый тип Action. Именно это и препятствует передаче неправильных команд методу Conveyor. Конечно, такое преобразование можно организовать принудительно с помощью приведения типов, но это было бы преднамеренным, а не случайным или неумышленным действием. Кроме того, вероятность неумышленной передачи пользователем неправильных ко манд методу Conveyor сводится с минимуму благодаря тому, что эти команды обо значены символическими именами в перечислении.
В приведенном выше примере обращает на себя внимание еще одно интересное обстоятельство: перечислимый тип используется для управления оператором switch. Как упоминалось выше, перечисления относятся к целочисленным типам данных, и поэтому их вполне допустимо использовать в операторе switch.
ГЛАВА 13. Обработка исключительных ситуаций
Исключительная ситуация, или просто исключение, происходит во время выполнения. Используя под систему обработки исключительных ситуаций в С#, можно обрабатывать структурированным и контроли руемым образом ошибки, возникающие при выполнении программы. Главное преимущество обработки исключи тельных ситуаций заключается в том, что она позволяет ав томатизировать получение большей части кода, который раньше приходилось вводить в любую крупную програм му вручную для обработки ошибок. Так, если программа написана на языке программирования без обработки ис ключительных ситуаций, то при неудачном выполнении методов приходится возвращать коды ошибок, которые не обходимо проверять вручную при каждом вызове метода. Это не только трудоемкий, но и чреватый ошибками про цесс. Обработка исключительных ситуаций рационализи рует весь процесс обработки ошибок, позволяя определить в программе блок кода, называемый обработчиком исклю чений и выполняющийся автоматически, когда возникает ошибка. Эго избавляет от необходимости проверять вруч ную, насколько удачно или неудачно завершилась конкрет ная операция либо вызов метода. Если возникнет ошибка, она будет обработана соответствующим образом обработ чиком ошибок.
Обработка исключительных ситуаций важна еще и по тому, что в С# определены стандартные исключения для типичных программных ошибок, например деление на нуль или выход индекса за границы массива. Для реаги рования на подобные ошибки в программе должно быть организовано отслеживание и обработка соответствующих исключительных ситуаций. Ведь в конечном счете для успешного программирования на C# необходимо научиться умело пользоваться подсистемой обработки исключи тельных ситуаций. Класс System.Exception
В C# исключения представлены в виде классов. Все классы исключений должны быть производными от встроенного в C# класса Exception, являющегося частью про странства имен System. Следовательно, все исключения являются подклассами класса Exception.
К числу самых важных подклассов Exception относится класс SystemException. Именно от этого класса являются производными все исключения, генерируемые испол няющей системой C# (т.е. системой CLR). Класс SystemException ничего не добавляет к классу Exception, а просто определяет вершину иерархии стандартных исключений.
В среде .NET Framework определено несколько встроенных исключений, являю щихся производными от класса SystemException. Например, при попытке выпол нить деление на нуль генерируется исключение DivideByZeroException. Как будет показано далее в этой главе, в C# можно создавать собственные классы исключений, производные от класса Exception. Основы обработки исключительных ситуаций
Обработка исключительных ситуаций в C# организуется с помощью четырех клю чевых слов: try, catch, throw и finally. Они образуют взаимосвязанную подсистему, в которой применение одного из ключевых слов подразумевает применение другого. На протяжении всей этой главы назначение и применение каждого из упомянутых выше ключевых слов будет рассмотрено во всех подробностях. Но прежде необходимо дать общее представление о роли каждого из них в обработке исключительных ситуа ций. Поэтому ниже кратко описан принцип их действия.