这只是一个“我很好奇”的问题。
在深入 C# 中,Jon Skeet 谈到了 lambda 表达式:
“如果有一个非空返回类型,那么每个代码路径都必须返回一个兼容的值。” (第 233 页)
脚注然后说:
“当然,抛出异常的代码路径不需要返回值,可检测的无限循环也不需要。” (第 233 页)
我想知道什么构成不可检测的无限循环?
这只能通过逻辑来完成吗?还是通过使用数据库或文件系统等外部因素来完成?
这只是一个“我很好奇”的问题。
在深入 C# 中,Jon Skeet 谈到了 lambda 表达式:
“如果有一个非空返回类型,那么每个代码路径都必须返回一个兼容的值。” (第 233 页)
脚注然后说:
“当然,抛出异常的代码路径不需要返回值,可检测的无限循环也不需要。” (第 233 页)
我想知道什么构成不可检测的无限循环?
这只能通过逻辑来完成吗?还是通过使用数据库或文件系统等外部因素来完成?
Jon 所指的内容在规范的第 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 节。
使用外部资源甚至滥用接口等工具来创建无限循环非常简单。
例如:
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());