Бесконечно ли обрабатываются бесконечные циклы в .NET как особый случай? - PullRequest
20 голосов
/ 06 сентября 2011

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

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

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

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

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

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

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

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

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

Ответы [ 2 ]

29 голосов
/ 06 сентября 2011

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

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

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

public int EndlessLoop()
{
    while (true)
    {
    }
}
3 голосов
/ 07 сентября 2011

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

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

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

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

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

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.
}
...