программирование. Руководство su P# a n Reference в herbert schildt полное руководство с 0 герберт шилдт
![]()
|
ГЛАВА 5 Управляющие операторы В этой главе речь пойдет об операторах, управляющих ходом выполнения программы на С#. Управляющие операторы разделяются на три категории: операторы выбора , к числу которых относятся операторы if и switch, итерационные операторы, в том числе операторы цикла for, while, do‑while и foreach, а также операторы перехода: break, continue, goto, return и throw. За исключением оператора throw, который является неотъемлемой частью встроенного в C# механизма обработки исключительных ситуаций, рассматриваемого в главе 13, все остальные управляющие операторы представлены в этой главе. Оператор if Оператор i f уже был представлен в главе 2, а здесь он рассматривается более подробно. Ниже приведена полная форма этого оператора: if ( условие) оператор ; else оператор ; где условие – это некоторое условное выражение, а оператор – адресат операторов if и else. Оператор else не является обязательным. Адресатом обоих операторов, if и else, могут также служить блоки операторов. Ниже приведена общая форма оператора i f, в котором используются блоки операторов. if ( условие) { последовательность операторов else { последовательность операторов } Если условное выражение оказывается истинным, то выполняется адресат оператора if. В противном случае выполняется адресат оператора else, если таковой существует. Но одновременно не может выполняться и то и другое. Условное выражение, управляющее оператором if, должно давать результат типа bool. Ниже приведен пример простой программы, в которой операторы if и else используются для того, чтобы сообщить, является ли число положительным или отрицательным. // Определить, является ли числовое значение положительным или отрицательным. using System; class PosNeg { static void Main() { int i; for(i=‑5; i <= 5; i++) { Console.Write("Проверка " + i + ": "); if(i < 0) Console.WriteLine("отрицательное число"); else Console.WriteLine("положительное число"); } } } Результат выполнения этой программы выглядит следующим образом. Проверка ‑5 отрицательное число Проверка ‑4 отрицательное число Проверка ‑3 отрицательное число Проверка ‑2 отрицательное число Проверка ‑1 отрицательное число Проверка 0 положительное число Проверка 1 положительное число Проверка 2 положительное число Проверка 3 положительное число Проверка 4 положительное число Проверка 5 положительное число Если в данном примере значение переменной i оказывается меньше нуля, то выполнятся адресат оператора if . В противном случае выполняется адресат оператора else, одновременно они не выполняются. Вложенные операторы if Вложенным называется такой оператор if, который является адресатом другого оператора if или же оператора else. Вложенные операторы if очень часто применяются в программировании. Что же касается их применения в С#, то не следует забывать, что любой оператор else всегда связан с ближайшим оператором if, т.е. с тем оператором if, который находится в том же самом блоке, где и оператор else, но не с другим оператором else. Рассмотрим следующий пример. if (i == Ю) { if (j < 20) ‑a = b; if(k > 100) с = d; else a = с; // этот оператор else связан с оператором if(k > 100) } else a = d; // этот оператор else связан с оператором if(i == 10) Как следует из комментариев к приведенному выше фрагменту кода, последний оператор else не связан с оператором if (j < 20), поскольку они не находятся в одном и том же блоке, несмотря на то, что этот оператор является для него ближайшим оператором if без вспомогательного оператора else. Напротив, последний оператор else связан с оператором if (i == 10). А внутренний оператор else связан с оператором i f (k > 100), поскольку этот последний является для него ближайшим оператором i f в том же самом блоке. В приведенном ниже примере программы демонстрируется применение вложенного оператора if. В представленной ранее программе определения положительных и отрицательных чисел о нуле сообщалось как о положительном числе. Но, как правило, нуль считается числом, не имеющим знака. Поэтому в следующей версии данной программы о нуле сообщается как о числе, которое не является ни положительным, ни отрицательным. // Определить, является ли числовое значение // положительным, отрицательным или нулевым. using System; class PosNegZero { static void Main() { int i; for(i=‑5; i <= 5; i++) { Console.Write("Проверка " + i + ": "); if(i < 0) Console.WriteLine("отрицательное число"); else if(i == 0) Console.WriteLine("число без знака"); else Console.WriteLine("положительное число"); } } } Ниже приведен результат выполнения этой программы. Проверка ‑5: отрицательное число Проверка ‑4: отрицательное число Проверка ‑3: отрицательное число Проверка ‑2: отрицательное число Проверка ‑1: отрицательное число Проверка 0: число без знака Проверка 1: положительное число Проверка 2: положительное число Проверка 3: положительное число Проверка 4: положительное число Проверка 5: положительное число Конструкция if‑else‑if В программировании часто применяется многоступенчатая конструкция if‑else‑if, состоящая из вложенных операторов if. Ниже приведена ее общая форма. if( условие) оператор ; else if (условие) оператор ; else if ( условие) оператор; else оператор ; Условные выражения в такой конструкции вычисляются сверху вниз. Как только обнаружится истинное условие, выполняется связанный с ним оператор, а все остальные операторы в многоступенчатой конструкции опускаются. Если ни одно из условий не является истинным, то выполняется последний оператор else, который зачастую служит в качестве условия, устанавливаемого по умолчанию. Когда же последний оператор else отсутствует, а все остальные проверки по условию дают ложный результат, то никаких действий вообще не выполняется. В приведенном ниже примере программы демонстрируется применение многоступенчатой конструкции if‑else‑if. В этой программе обнаруживается наименьший множитель заданного целого значения, состоящий из одной цифры. // Определить наименьший множитель заданного // целого значения, состоящий из одной цифры. using System; class Ladder { static void Main(), { int num; for(num = 2; num < 12; num++) { if((num % 2) == 0) Console.WriteLine("Наименьший множитель числа " + num + " равен 2.") else if((num % 3) == 0) Console.WriteLine("Наименьший множитель числа " + num + " равен 3.") else if((num % 5) == 0) Console.WriteLine("Наименьший множитель числа " + num + " равен 5.") else if((num % 7) == 0) Console.WriteLine("Наименьший множитель числа " + num + " равен 7.") else Console.WriteLine(num + " не делится на 2, 3, 5 или 7."); } } } Вот к какому результату приводит выполнение этой программы. Наименьший множитель числа 2 равен 2 Наименьший множитель числа 3 равен 3 Наименьший множитель числа 10 равен 2 11 не делится на 2, 3, 5 или 7. Как видите, последний оператор else выполняется лишь в том случае, если не удается выполнить ни один из предыдущих операторов. Оператор switch Вторым оператором выбора в C# является оператор switch, который обеспечивает многонаправленное ветвление программы. Следовательно, этот оператор позволяет сделать выбор среди нескольких альтернативных вариантов дальнейшего выполнения программы. Несмотря на то что многонаправленная проверка может быть организована с помощью последовательного ряда вложенных операторов if, во многих случаях более эффективным оказывается применение оператора switch. Этот оператор действует следующим образом. Значение выражения последовательно сравнивается с константами выбора из заданного списка. Как только будет обнаружено совпадение с одним из условий выбора, выполняется последовательность операторов, связанных с этим условием. Ниже приведена общая форма оператора switch. switch (выражение) { case константа1: последовательность операторов break; case константа2: последовательность операторов break; case константаЗ: последовательность операторов break; default: последовательность операторов break; } Заданное выражение в операторе switch должно быть целочисленного типа (char, byte, short или int), перечислимого или же строкового. (О перечислениях и символьных строках типа string речь пойдет далее в этой книге.) А выражения других типов, например с плавающей точкой, в операторе switch не допускаются. Зачастую выражение, управляющее оператором switch, просто сводится к одной переменной. Кроме того, константы выбора должны иметь тип, совместимый с типом выражения. В одном операторе switch не допускается наличие двух одинаковых по значению констант выбора. Последовательность операторов из ветви default выполняется в том случае, если ни одна из констант выбора не совпадает с заданным выражением. Ветвь default не является обязательной. Если же она отсутствует и выражение не совпадает ни с одним из условий выбора, то никаких действий вообще не выполняется. Если же происходит совпадение с одним из условий выбора, то выполняются операторы, связанные с этим условием, вплоть до оператора break. Ниже приведен пример программы, в котором демонстрируется применение оператора switch. // Продемонстрировать применение оператора switch. using System; class SwitchDemo { static void Main() { int i; for(i=0; i<10; i++) switch(i) { case 0: Console.WriteLine("i равно нулю"); break; case 1: Console.WriteLine("i равно единице"); break; case 2: Console.WriteLine("i равно двум"); break; case 3: Console.WriteLine("i равно трем"); break; case 4: Console.WriteLine ("i равно четырем"); break; default: ( Console.WriteLine("i равно или больше пяти"); break; } } } Результат выполнения этой программы выглядит следующим образом. i равно нулю. i равно единице. i равно двум. i равно трем. i равно четырем. i равно или больше пяти i равно или больше пяти i равно или больше пяти i равно или больше пяти i равно или больше пяти Как видите, на каждом шаге цикла выполняются операторы, связанные с совпадающей константой выбора, в обход всех остальных операторов. Когда же значение переменной i становится равным или больше пяти, то оно не совпадает ни с одной из констант выбора, а следовательно, выполняются операторы из ветви default. В приведенном выше примере оператором switch управляла переменная i типа int. Как пояснялось ранее, для управления оператором switch может быть использовано выражений любого целочисленного типа, включая и char. Ниже приведен пример применения выражения и констант выбора типа char в операторе switch. // Использовать элементы типа char для управления оператором switch. using System; class SwitchDemo2 { static void Main() { char ch; for(ch='A'; ch<= ' E'; ch++) switch (ch) { case 'A1: Console.WriteLine("ch содержит A"); break; case 'В': Console.WriteLine("ch содержит В"); break; case 'С': Console.WriteLine("ch содержит С"); break; case ' D' : Console.WriteLine("ch содержит D"); break; case 'E': Console.WriteLine("ch содержит E"); break; } } } Вот какой результат дает выполнение этой программы. ch содержит А ch содержит В ch содержит С ch содержит D ch содержит Е Обратите в данном примере внимание на отсутствие ветви default в операторе switch. Напомним, что ветвь default не является обязательной. Когда она не нужна, ее можно просто опустить. Переход последовательности операторов, связанных с одной ветвью case, в следующую ветвь case считается ошибкой, поскольку в C# должно непременно соблюдаться правило недопущения "провалов" в передаче управления ходом выполнения программы. Именно поэтому последовательность операторов в каждой ветви case оператора switch оканчивается оператором break. (Избежать подобных "провалов", можно также с помощью оператора безусловного перехода goto, рассматриваемого далее в этой главе, но для данной цели чаще применяется оператрр break.) Когда в последовательности операторов отдельной ветви case встречается оператор break, происходит выход не только из этой ветви, но из всего оператора switch, а выполнение программы возобновляется со следующего оператора, находящегося за пределами оператора switch. Последовательность операторов в ветви default также должна быть лишена ''провалов'7, поэтому она завершается, как правило, оператором break. Правило недопущения "провалов" относится к тем особенностям языка С#, которыми он отличается от С, C++ и Java. В этих языках программирования одна ветвь case может переходить (т.е. "проваливаться") в другую. Данное правило установлено в C# для ветвей case по двум причинам. Во‑первых, оно дает компилятору возможность свободно изменять порядок следования последовательностей операторов из ветвей case для целей оптимизации. Такая реорганизация была бы невозможной, если бы одна ветвь case могла переходить в другую. И во‑вторых, требование завершать каждую ветвь case явным образом исключает непроизвольные ошибки программирования, допускающие переход одной ветви case в другую. Несмотря на то что правило недопущения "провалов" не допускает переход одной ветви case в другую, в двух или более ветвях case все же разрешается ссылаться с помощью меток на одну и ту же кодовую последовательность, как показано в следующем примере программы. // Пример "проваливания" пустых ветвей case. using System; class EmptyCasesCanFall { static void Main() { int i; for(i=l; i < 5; i++) switch(i) { case 1: case 2: case 3: Console.WriteLine("i равно 1, 2 или 3м); break; case 4: Console.WriteLine("i равно 4"); break; } } } Ниже приведен результат выполнения этой программы. Если значение переменной i в данном примере равно 1, 2 или 3, то выполняется первый оператор, содержащий вызов метода WriteLine (). Такое расположение нескольких меток ветвей case подряд не нарушает правило недопущения "провалов"; поскольку во всех этих ветвях используется одна и та же последовательность операторов. Расположение нескольких меток ветвей case подряд зачастую применяется в том случае, если у нескольких ветвей имеется общий код. Благодаря этому исключается излишнее дублирование кодовых последовательностей. Вложенные операторы switch Один оператор switch может быть частью последовательности операторов другого, внешнего оператора switch. И такой оператор switch называется вложенным. Константы выбора внутреннего и внешнего операторов switch могут содержать общие значения, не вызывая никаких конфликтов. Например, следующий фрагмент кода является вполне допустимым. |