Оператор
goto
может иметь одну из следующих форм:
goto
идентификатор',
goto case
выражение-константа',
goto default.
В первом случае
идентификатор
указывает на оператор метки вида:
идентификатор:
Если в текущем методе такой метки нет, при компиляции возникнет ошибка. Еще одно важное правило:
goto
может применяться для выхода из вложенного цикла. Однако если он находится вне области видимости метки, при компиляции возникнет ошибка. Так что перейти внутрь вложенного цикла невозможно.
Ниже приложение просматривает простой массив, читая каждое значение, пока не встретит признак завершения, после чего производится выход из цикла. Оператор
goto
на самом деле действует, как
break,
в том смысле, что передает управление из цикла
foreach.
using System;
using System.Collections;
Glass MyArray
{
public ArrayList words;
public const string TerminatingWord = "stop";
public MyArrayO {
words = new ArrayListQ;
for (int 1 = 1; i <= 5; i++) words.Add(i.ToStringO); words.Add(TerminatingWord);
for (int 1 = 6; i <= 10; i++) words.Add(l.ToStringO); } }
class GototApp {
public static void Main()
{
MyArray myArray = new MyArrayO;
Console.WriteLine("Обработка массива ...");
foreach (string word in myArray.words) {
if (word == MyArray.TerminatingWord) goto finished;
Console.WriteLine(word); }
finished:
Console.WriteLine("Обработка массива закончена"); } >
Что касается применения здесь
goto,
кто-то может сказать, что с не меньшей эффективностью можно применить оператор
break
и в метке не будет нужды. Мы рассмотрим другую форму
goto, к
вы увидите, что схожие проблемы могут быть решены только с его помощью.
Рассказывая об операторе
switch, я
говорил, что в С# не поддерживается передача управления вниз. Да если б и поддерживалась, нельзя было бы решить следующую проблему. Скажем, у нас есть класс
Payment,
принимающий разные формы платежей или платежных средств: Visa, American Express, MasterCard, наличные и списание со счета (по сути кредит). Поскольку Visa, American Express и MasterCard — все являются кредитными картами, мы хотим объединить их под одной case-меткой и обрабатывать единообразно. При списании со счета нам потребуется вызвать специфический для этого случая метод, а при покупке за наличные — только распечатать квитанцию. Кроме того, квитанция должна распечатываться и во всех других случаях. Как мы можем иметь case-метки для трех разных ситуаций, но при этом, чтобы в первых двух случаях (кредитные карты и списание со счета) мы переходили на третью case-метку? Решение проблемы — хороший пример использования
goto:
using System;
enum Tenders ; int {
ChargeOff,
Cash,
Visa,
MasterCard,
AmericanExpress };
class Payment <
public Payment(Tenders tender)
<
this.Tender = tender;
}
protected Tenders tender; public Tenders Tender {
get
{
return this.tender;
}
set
{
this.tender = value;
} }
protected void ChargeOffQ {
Console.WriteLineC'CnncaHMe со счета,");
}
protected bool ValidateCreditCardQ
{
Console.WriteLine("Карта принимается.");
return true; }
protected void ChargeCreditCardO {
Console.WriteLine("Списание с кредитной карты");
}
protected void PrintReceiptQ
{
Console.WriteLine("Cnacn6o, всегда вам рады.");
}
public void ProcessPaymentO <
switch ((int)(this.tender))
{
case (int)Tenders.ChargeOff: ChargeOffQ; goto case Tenders.Cash;
case (int)Tenders.Visa:
case (int)Tenders.MasterCard:
case (int)Tenders.AmericanExpress:
if (ValidateCreditCardO) ChargeCreditCardO;
goto case Tenders.Cash;
case (int)Tenders.Cash: PrintReceiptO; break;
default:
Console.WriteLine("\nH3BKHHTe - недопустимое "+
"платежное средство."); break;
}
} }
class GotoCaseApp {
public static void Main() {
Payment payment = new Payment(Tenders.Visa); payment. ProcessPaymentO; } }
Вместо того, чтобы решать проблему противоестественным способом, мы просто указали компилятору, что по завершении обработки кредитной карты или списании со счета нужно перейти к ветке, обрабатывающей наличные. Последнее замечание: если в С# вы выходите за пределы case-метки, использовать оператор
break
нельзя — компилятор укажет, что код недоступен.
Последняя форма оператора
goto
позволяет переходить на метку
default
в операторе
switch,
что дает возможность написать один блок кода, который будет выполнен в результате нескольких вычислений в
switch.