Назначение управляющих операторов. Используются в рамках методов, задают логику выполнения программы, являются основным средством реализации алгоритма.
Различаются следующие категории управляющих операторов:
§ операторы выбора. Вводятся ключевыми словами if, if … else …, switch,
§ итеративные операторы. Вводятся ключевыми словами while, do … while, for, foreach,
§ операторы перехода (в рамках методов). Вводятся ключевыми словами goto, break, continue.
if, if … else …
После ключевого слова if располагается взятое в круглые скобки условное выражение (булево выражение), следом за которым располагается оператор (блок операторов) произвольной сложности.
Далее в операторе if … else … после ключевого слова else размещается ещё один оператор.
В силу того, что в C# отсутствуют предопределённые алгоритмы преобразования значений к булевскому типу, в условное выражение должно быть выражением типа bool – переменной, константой, либо выражением на основе операций сравнения и логических операций.
В соответствии с синтаксисом условного оператора в части else (если таковая имеется) располагается блок операторов. Частный случай оператора – оператор if.
Какой бы сложности ни были составляющие части if…else… – это всего лишь ДВЕ равноправных части одного оператора. “Каскад” в if…else… – это всего лишь оператор (блок), содержащий вхождение if или if…else… операторов.
if (…)
{
}
else
{
if (…)
{
}
else
{
}
}
переписывается
if (…)
{
}
else
if (…)
{
}
else
{
}
Вложенный (Nesting) if. Оператор if часто сам в свою очередь является условным оператором произвольной сложности.
И в этом случае if…else… оператор включает ДВЕ части.
if (…)
{
if (…)
{
}
else
{
}
}
else
{
}
переписывается
if (…) if (…)
{
}
else
{
}
else
{
}
Главное - не перепутать соответствующие части if…else… оператора.
Ещё одно важное замечание связано с использованием “простых” (не блоков) операторов. Невозможно построить оператор if…else… на основе одиночного оператора объявления.
if (true) int XXX = 125;
if (true) int XXX = 125; else int ZZZ = 10;
Такие конструкции воспринимаются как ошибочные. Всё-таки в C# одиночный оператор это не блок, и ставить в зависимость от условия (пусть даже всегда истинного) такое ответственное дело как создание объекта здесь не принято.
Совсем другое дело при работе с блоками операторов!
if (true) {int XXX = 125;}
if (true) {int XXX = 125;} else {int ZZZ = 10;}
Даже в таких примитивных блоках своя область видимости и создаваемые в них объекты никому не мешая существуют по своим собственным правилам.
Switch
При описании синтаксиса оператора switch использована нотация Бэкуса-Наура (БНФ).
Таким образом, минимальный switch оператор имеет следующий вид:
int val;
::::::::::
switch (val)
{
default: break; // Список операторов пуст.
}
Более сложные образования:
int val;
::::::::::
switch (val)
{
case 0: break;
}
::::::::::
switch (val)
{
case 0: break;
default: break; // Список операторов пуст.
}
::::::::::
switch (val)
{
default: … break; // defaul БЛОКИРУЕТ выполнение операторов
// всех ниже лежащих CaseЭлементов.
case 100: … break;
}
::::::::::
switch (val)
{
default: // default БЛОКИРУЕТ выполнение операторов
// всех ниже лежащих CaseЭлементов, кроме операторов,
// входящих в CaseЭлемент под меткой 100.
case 100: … break;
case 1: … break;
case 10: … break;
}
Поскольку при выполнении модуля выбор списков операторов для выполнения в рамках CaseЭлемента определяется значением константных выражений в case метках, константные выражения ВСЕХ меток данного switchБлока должны различаться ПО СВОИМ ЗНАЧЕНИЯМ.
Следующий пример некорректен. Константные выражения в списках разделённых меток CaseЭлемента
case 1+1: case 2: … break;
различаются ПО ФОРМЕ (1+1 и 2), а НЕ ПО ЗНАЧЕНИЮ!
По тем же причинам в рамках switch оператора может быть не более одного вхождения метки default.
Списки операторов в CaseЭлементах НЕ могут включать операторы объявления. switchОператор строится на основе ОДНОГО блока, разделяемого метками на фрагменты, выполнение которых производится в зависимости от значений константных выражений в case метках. Разрешение объявления констант и переменных в CaseЭлементе означает риск обращения к ранее необъявленной переменной.
switch (val)
{
case 0:
int XXX = 100; // Нельзя!
break;
case 1:
XXX += 125;
break;
}
Каждый CaseЭлемент в обязательном порядке ЗАВЕРШАЕТСЯ оператором-терминатором, который является ОБЩИМ для ВСЕХ операторов данного CaseЭлемента:
int val, XXX;
:::::
switch (val)
{
case 0:
if (XXX == 25) {XXX *= -1; break;}
else XXX = 17;
goto default; // Общий терминатор.
case 1:
XXX += 125;
break; // Общий терминатор.
default:
return XXX; // Общий терминатор.
}
While
ОператорWHILE ::= while (УсловиеПродолжения) Оператор
УсловиеПродолжения ::= БулевоВыражение
Здесь опять же:
Оператор ::= Оператор
::= БлокОператоров
Правило выполнения этого итеративного опера состоит в следующем: сначала проверяется условие продолжения оператора и в случае, если значение условного выражения равно true, соответствующий оператор (блок операторов) выполняется.
Невозможно построить операторWHILE на основе одиночного оператора объявления. Оператор
while (true) int XXX = 0;
С самого первого момента своего существования (ещё до начала трансляции!) сопровождается предупреждением:
Embedded statement cannot be a declaration or labeled statement.
do … while
ОператорDOWHILE ::= do Оператор while (УсловиеПродолжения)
УсловиеПродолжения ::= БулевоВыражение
Оператор ::= Оператор
::= БлокОператоров
Разница с ранее рассмотренным оператором цикла состоит в том, что здесь сначала выполняется оператор (блок операторов), а затем проверяется условие продолжения оператора.
ВыраженияИнициализации, УсловиеПродолжения, ВыраженияШага в заголовке оператора цикла for могут быть пустыми. Однако наличие пары символов ‘;’ в заголовке цикла for обязательно.
Список выражений представляет собой разделённую запятыми последовательность выражений.
Следует иметь в виду, что оператор объявления также строится на основе списка выражений (выражений объявления), состоящих из спецификаторов типа, имён и, возможно, инициализаторов. Этот список завершается точкой с запятой, что позволяет рассматривать список выражений инициализации как самостоятельный оператор в составе оператора цикла for. При этом область видимости имён переменных, определяемых этим оператором, распространяется только на операторы, относящиеся к данному оператору цикла. Это значит, что переменные, объявленные в операторе инициализации данного оператора цикла НЕ МОГУТ быть использованы непосредственно после оператора до конца блока, содержащего этот оператор. А следующие друг за другом в рамках общего блока операторы МОГУТ содержать в заголовках одни и те же выражения инициализации.
операторFOR также невозможно построить на основе одиночного оператора объявления.