netlib.narod.ru< Назад | Оглавление | Далее >

Условия и циклы

В С# поддерживаются многие применяемые в С условные инструкции, инструкции цикла и управления выполнением программы. В этом разделе я рассмотрю инструкции, содержащие ключевые слова if, else, do, while, switch, case, default, for, foreach, in, break, continue и goto.

Конструкции if и else выглядят точно так же, как в С:

  if (a == 5)
  {
      ...
  }
  else if (a < 5)
  {
      ...
  }
  else
  {
      ...
  }

Однако в С# выражения в скобках должны иметь тип bool. Такое ограничение позволяет избежать общеизвестного подводного камня языка С — ошибочного использования в проверяемом выражении оператора присваивания вместо оператора сравнения:

  if (a = 5)

Такой оператор вызовет в С# ошибку компиляции, и скажите за это спасибо С#.

Но, конечно, ни один компилятор не обеспечивает полной защиты от рассеянности программиста. В одной из своих первых программ на С# я определил переменную trigger типа bool, но вместо инструкции

  if (trigger)

я, чтобы сделать программу чуть понятнее, хотел ввести

  if (trigger == true)

Но, к сожалению, я ввел:

  if (trigger = true)

Это совершенно корректная, с точки зрения С#, инструкция, но, очевидно, она делает не то, что я хотел.

Кроме того, С# поддерживает инструкции do и while. Можно проверять условие перед выполнением блока:

  while (a < 5)
  {
      ...
  }

или после:

  do
  {
      ...
  }
  while (a < 5);

Здесь выражение также должно иметь тип bool. Во втором случае блок выполнится хотя бы раз независимо от значения а.

В конструкции switch/case языка С# есть ограничение, которого нет в С. В С допускается инструкция:

  switch (a)
  {
  case 3:
       b = 7;
                // В С# запрещено прохождение через case.
  case 4:
       с = 3;
       break;

  default:
       b = 2;
       с = 4;
       break;
  }

Если а равно 3, выполнится первый оператор, затем программа «перешагнет» через case, в котором а равно 4. Может, вы именно так и задумали, но возможно, что вы просто забыли поставить инструкцию break. Чтобы избежать ситуаций такого рода, компилятор С# сообщает об ошибке. С# позволяет проходить через case, только если case не содержит инструкций. Вот какая конструкция допустима в С#:

  switch (a)
  {
  case 3:
  case 4:
       b = 7;
       с = 3;
       break;

  default:
       b = 2;
       с = 4;
       break;
  }

Если требуется нечто более сложное, можно использовать инструкцию goto, описанную в этом разделе далее.

Одна из приятных возможностей C#: в инструкции switch можно использовать строковую переменную, сравниваемую в инструкциях case со строковыми константами:

  switch (strCity)
  {
  case "Boston":
       ...
       break;

  case "New York":
       ...
       break;

  case "San Francisco":
       ...
       break;

  default:
       ...
       break;
  }

Конечно, такой фрагмент кода вызовет ужас у заботящихся о производительности программистов на С или C++. Все эти сравнения строк просто не могут быть особо эффективными. На самом деле, благодаря технологии интернирования строк (string interning), заключающейся в поддержке таблицы всех используемых в программе уникальных строк, он работает гораздо быстрее, чем может показаться.

Цикл for выглядит в С# точно так же, как в С и C++:

  for (i = 0; i < 100; i += 3)
  {
      ...
  }

Как и в C++, в С# широко используется определение переменной цикла прямо в инструкции for:

  for (float f = 0; f < 10.05f; f += 0.1f)
  {
      ...
  }

Удобным дополнением к этому типу цикла является инструкция foreach, позаимствованная С# из Visual Basic. Предположим, arr — массив значений типа float. Если требуется показать все его элементы в одной строке, разделив их пробелами обычно делают так:

  for {int i = 0; i < arr.Length; i++)
      Console.Write("{0} ", arr[i]);

Инструкция foreach, в которой используется ключевое слово in, упрощает эту операцию:

  foreach (float f in arr)
      Console.Write("{0} ", f);

Для параметра цикла foreach (в данном случае переменной f) надо в инструкции foreach указать тип данных; в следующем за foreach блоке инструкций параметр цикла доступен только для чтения. Следовательно, foreach не годится для инициализации элементов массива:

  int[] arr = new int[100];

  foreach (int i in arr)   // Так нельзя!
      i = 55;

Интересно, что инструкция foreach может работать не только с массивами, но и с любыми классами, реализующими интерфейс IEnumerable, определенный в пространстве имен System.Collections. Более ста классов .NET Framework реализуют интерфейс IEnumerable. (Здесь я лишь коснусь интерфейсов, а в главе 8 рассмотрю их подробно.)

Инструкция break обычно используется в конструкциях switch/case, а также для выхода из циклов while, do, for и foreach. Инструкция continue служит для перехода к концу блока, выполняемого в цикле while, do, for или foreach и выполнении следующей итерации цикла (если эта итерация должна выполняться согласно условию цикла).

И, наконец, инструкция goto:

  goto MyLabel;
      ...
  MyLabel:

полезна для выхода из блоков с большой вложенностью и написания запутанного кода. Кроме того, в С# поддерживается инструкция goto в конструкции switch/case для перехода к другой ветви:

  switch (a)
  {
  case 1:
       b = 2;
       goto case 3;

  case 2:
       с = 7;
       goto default;

  case 3:
       с = 5;
       break;

  default:
       b = 2;
       break;
  }

Если вместо break используется goto, то инструкция break в конце ветви не нужна. Эта возможность компенсирует запрет проходить через case.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz