С# - Как создать бесконечный цикл без обнаружения?
Это просто вопрос "Я любопытен".
В С# в глубине Джон Скит говорит о лямбда-выражениях:
"если существует невозвратный тип возврата, каждый путь кода должен возвращать совместимое значение". (Страница 233)
В следующей сноске говорится:
"Исключение исключений для путей кода, конечно, не обязательно должно возвращать значение, а также не обнаруживать бесконечных циклов". (Страница 233)
Мне интересно, что представляет собой неопределяемый бесконечный цикл?
Можно ли это сделать только логикой? или это делается с использованием внешних факторов, таких как база данных или файловая система?
Ответы
Ответ 1
То, что Джон имеет в виду, описано в разделе 8.1 спецификации. Компилятор может обнаруживать только очень простые бесконечные циклы, например:
while(true) { if (0 != 0) return 123; }
Компилятор достаточно умен, чтобы увидеть, что возврат никогда не достигается, и поэтому цикл работает вечно. Юридически, хотя и сумасшедший, сказать:
int M() { while(true) { } }
потому что, хотя нет пути, который возвращает int, также нет пути, который возвращается без возврата int!
Компилятор недостаточно умен, чтобы найти другие типы бесконечных циклов. Например:
int x = 123;
while(true) { if (x * 0 != 0) break; }
Это явно бесконечный цикл. Но компилятор этого не знает. Компилятор говорит "хорошо, может быть, есть какое-то значение x, где x * 0 не равно нулю, поэтому разрыв возможен, поэтому это не бесконечный цикл". Мы с вами знаем, что это невозможно, потому что мы знаем математику, но компилятор этого не делает.
Прочтите раздел 8.1, если хотите детали.
Ответ 2
Это довольно тривиально, чтобы создать бесконечный цикл с использованием внешних источников или даже злоупотреблять инструментами, такими как интерфейсы.
Например:
public interface INumbers
{
int GetNumber(int arg);
}
public class StaticNumber : INumbers
{
public int GetNumber(int arg)
{
return 1;
}
}
public void DoStuff(INumbers num)
{
int i = 42;
while ((i = num.GetNumber(i)) != 0)
{
;
}
}
а затем простой
Action action = () => DoStuff(new StaticNumber());