Как оператор goto работает в этом примере?

Я изучаю этот пример кода:

class Program
{
    static void Main(string[] args)
    {
        int x = 10;
        int y = 10;

        int generate=0;

        string [,] myArrayTable = new string[x, y];

        Console.WriteLine("Enter a seek number: ");
        string cautat = Console.ReadLine();

        for (int i = 0; i < x; i++)
        {
            for(int j = 0;j < y; j++)
            {
                myArrayTable[i, j] = (generate++).ToString();
            }
        }

        for(int i=0;i<x;i++)
        {
            for(int j=0;j<y;j++)
            {
                if(cautat.Equals(myArrayTable[i,j]))
                {
                    goto Found; 
                }
            }
        }

        goto NotFound;

        Found: 
          Console.WriteLine("Numarul a fost gasit");

        NotFound:
         Console.WriteLine("Numarul nu a fost gasit !");

        Console.ReadKey();
    }
}

Я не понимаю, почему была вызвана инструкция «Not Found» и соответствующее сообщение выводится на консоль, если я ввожу число поиска, например 10, в этом случае выполняется оператор goto: Found, поэтому оператор goto: NotFound никогда не будет вызываться, но тем не менее его соответствующее сообщение печатается на консоли, я не понимаю, как в этом случае программа никогда не переходит на эту метку «NotFound».

Пожалуйста, если вы сейчас поможете мне с этим...

Спасибо


person Mircea    schedule 31.08.2010    source источник
comment
Отличный пример goto неправильного использования   -  person Andrey    schedule 31.08.2010
comment
Вы действительно должны изменить структуру, чтобы не использовать goto в любом случае. Как правило, это не считается хорошей практикой, поэтому вы получите много головокружения при проверке кода, и это, как правило, невозможно поддерживать. Откровенно говоря, от этого исходит безошибочный запах кода.   -  person Cruachan    schedule 31.08.2010


Ответы (6)


Eww goto, я бы использовал оператор and if/else, но если вам нужен goto:

Found: 
  Console.WriteLine("Numarul a fost gasit");
  goto End;
NotFound:
  Console.WriteLine("Numarul nu a fost gasit !");
End:
Console.ReadKey();
person SwDevMan81    schedule 31.08.2010

Я бы переписал этот код, чтобы избежать использования goto:

string message;
if (myArrayTable.Cast<string>().Contains(cautat)) {
    message = "Found";
} else {
    message = "Not found!";
}
Console.WriteLine(message);
person Mark Byers    schedule 31.08.2010

Он вызывается, потому что ваш код внутри метки Found не имеет ничего, что заставляло бы его пропустить код с меткой NotFound (если вы не вызовете goto снова, выполнение не пройдет через метку, а не пропустит ее).

При этом не используйте goto! Я даже скажу, что это всегда плохая идея и ее можно переписать.

В вашем случае вы можете добавить простой логический флаг, чтобы избавиться от вашего перехода:

static void Main(string[] args)
{
    int x = 10, y = 10;
    bool isFound = false;

    // Rest of the body

    for(int i=0;i<x;i++)
    {
        for(int j=0;j<y;j++)
        {
            if(cautat.Equals(myArrayTable[i,j]))
            {
                isFound = true;
                break;
            }
        }

        if(isFound)
            break;
    }

    if(isFound)
        Console.WriteLine("Numarul a fost gasit");
    else
        Console.WriteLine("Numarul nu a fost gasit!");

    Console.ReadKey();
}
person Justin Niessner    schedule 31.08.2010
comment
Эта перезапись всегда будет искать все элементы в массиве, даже если элемент уже найден. Этого можно избежать, добавив тест в цикл for или используя Contains. - person Mark Byers; 31.08.2010
comment
Gotos считаются жизнеспособной альтернативой для кода, возвращающего статус, когда другие методы слишком сложны и небрежны. Конечно, в этом случае goto лучше, чем логическое значение для выхода из цикла. - person Novikov; 31.08.2010
comment
@Марк Байерс - ты прав. Я просто удалял проблему Goto. Я обновил свой пример, чтобы выйти из циклов, как только что-то будет найдено (я бы включил пример «Содержит», но ОП никогда не говорит, что может использовать «Содержит»… и вы уже позаботились об этом). - person Justin Niessner; 31.08.2010
comment
@Nokikov, я бы, конечно, не рассматривал goto в данном случае жизнеспособный вариант. Если вы не хотите использовать логические значения для выхода из цикла, всегда есть метод Марка или альтернативное решение сделать это функцией и выполнить ранний возврат. - person Anthony Pegram; 31.08.2010
comment
@Nokikov - я согласен с @Anthony. Ни в коем случае форма или форма не являются приемлемым вариантом в этом случае. - person Justin Niessner; 31.08.2010
comment
Или вы можете выполнить проверку в первом наборе циклов double for и просто пропустить второй набор (и сохранить isFound=true без разрыва, как у вас было). Поскольку первый двойной цикл for устанавливает myArrayTable, вы также можете добавить туда проверку. - person SwDevMan81; 31.08.2010
comment
При этом не используйте goto! Я зайду так далеко, что скажу, что это всегда плохая идея и ее можно переписать. - У меня нет проблем, если это ваше мнение (я скорее согласен с Новиковым). Но вы утверждаете это так, как будто это 10 заповедей программирования, с чем я, в свою очередь, категорически не согласен. Я тоже редко нуждаюсь в gotos, но я думаю, что при правильном использовании, особенно для простого выхода из вложенных циклов (на одну метку, а не на 2, как в этом примере), это может быть самое элегантное, не говоря уже о самом простом решении. . - person Nicholas Petersen; 14.01.2015
comment
Тем не менее, двойные ярлыки здесь выглядят отвратительно. Лучше сделать следующее: а) установить переменную i сразу над циклом, так что если после выхода из цикла i ‹ x, вы знаете, что сломались раньше, и, таким образом, он был найден. б) еще лучше (это, вероятно, более чистый/ясный код), просто установите переменную bool wasFound, установите значение true при обнаружении и ЗАТЕМ разбейте на одну метку (END_LOOP). - person Nicholas Petersen; 14.01.2015

Потому что вы просто переходите к метке «Найден» и переходите к метке «Не найдено». Вам понадобится третья метка с именем EndFound и перейдите к ней после того, как вы ее нашли.

Found: 
    Console.WriteLine("Numarul a fost gasit");
    goto EndFound;
NotFound:
    Console.WriteLine("Numarul nu a fost gasit !");
EndFound:
person Novikov    schedule 31.08.2010

если вы не хотите, чтобы статусы «Not Found» выполнялись, если выполняются статусы «Found», используйте другой переход, чтобы пропустить часть NotFound. goto переходит к разделу, но это не означает, что раздел не будет выполнен, если к нему не перейти через goto. Помните, что код выполняется сверху вниз, поэтому, если вы каким-то образом не пропустите фрагмент кода, он будет выполняться.

пример:

Found:  
    Console.WriteLine("Numarul a fost gasit"); 

goto ReadKey;

NotFound: 
    Console.WriteLine("Numarul nu a fost gasit !"); 

ReadKey:
    Console.ReadKey(); 
person Jeremy    schedule 31.08.2010

Потому что после перехода к Found выполнение просто продолжается до следующей строки, которая оказывается строкой записи консоли «не найдена». Вам нужно добавить еще один goto, чтобы перепрыгнуть через это (или, что еще лучше, изменить его, чтобы полностью избежать goto)

Это именно такая проблема, что следует избегать gotos.

person James Curran    schedule 31.08.2010