Подтвердить что ты не робот

Являются ли явно бесконечные петли обработаны в .NET как особый случай?

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

    private int Example()
    {
        while (true)
        {
            if (some condition)
            {
               return 1;
            }
        }
    }

У вас есть явно бесконечный цикл и некоторый набор условий внутри цикла, которые заставляют цикл заканчиваться оператором return. Пусть в настоящее время игнорируется, почему я делал это, а не проверял условие завершения в предложении while, поскольку ответ запутан и неактуален. Я хочу знать, почему компилятор не отмечает это с помощью параметра "Нет" все пути возвращают значение ". ошибка, так как, строго говоря, не все пути возвращают значение. Случай, когда цикл while никогда не вводится (что, конечно, никогда не происходит) ничего не возвращает.

Теперь есть две причины, которые я могу себе представить: это побочный эффект оптимизации, который возникает по другим причинам, или этот случай явно обрабатывается компилятором, чтобы разрешить эту идиому. Мой инстинкт состоит в том, что это, вероятно, первый случай. Меня это совсем не удивляет, например, что это компилируется:

private int Example2()
{
   if (true) return 1;
}

Потому что компилятор видит константу true в if и оптимизирует условное значение. Я действительно не понимаю, почему это "исправило" первый пример.

О, и даже более странно, если какая-то оптимизация, которая избавляется от цикла, находится в игре, это компилируется:

    private int Example3()
    {
        while (true)
        {
            if (false)
            {
               return 1;
            }
        }
    }

Я бы подумал, что весь внутренний цикл будет оптимизирован, избавившись от всех действительных возвратов. Что на самом деле происходит здесь на уровне байт-кода/компилятора, что делает все это имеющим смысл?

4b9b3361

Ответ 1

Компилятор не отмечает это, потому что конец метода недоступен. Это не проблема - это только проблема, если вы можете дойти до конца метода (закрывающей скобки), не возвращая значения.

Это не вопрос оптимизации компилятора - это случай следования определениям достижимости, изложенным в спецификации.

Обратите внимание, что вам совсем не нужен оператор возврата... этот код бесполезен, но совершенно корректен:

public int EndlessLoop()
{
    while (true)
    {
    }
}

Ответ 2

Чтобы дать вам пример использования для этих типов бесконечных циклов, рассмотрите следующий код:

public int KeyboardChecker()
{
    while (true)
    {
        if (KeyHasBeenPressed())
        {
            HandleKeyPress();
        }
    }
}

Затем вы запускаете этот метод в своем собственном потоке, тем самым асинхронно обрабатывая ввод с клавиатуры (это шаблон опроса, наличие системы событий на месте обычно предпочтительнее).

Вы можете представить потоки, чтобы вернуть коды состояния, когда они закончены, поэтому возвращаемое значение метода - int. Однако, поскольку этот конкретный поток никогда не завершится, это не проблема вообще, что метод не содержит никакого оператора return. Разработчики С# знали об этих случаях использования и сделали вышеуказанный метод законным.

Обратите внимание, что общая проблема определения того, будет ли конкретный метод всегда возвращать значение, является неразрешимым (т.е. не может быть разрешена какой-либо компьютерной программой). Поэтому компилятор С# может жаловаться на код, который всегда будет возвращать значение (хотя он никогда не будет принимать программы, которые этого не делают):

public int DoWork()
{
    // The compiler doesn't figure out this will always be true.
    if (((int)Math.Sqrt(4)) == 2)
    {
        return 3;
    }
    // And therefore complains that not all code paths return a value for this method.
}