如果我这样做,我会得到一个
System.StackOverflowException
:
private string abc = "";
public string Abc
{
get
{
return Abc; // Note the mistaken capitalization
}
}
我明白为什么——属性引用自身,导致无限循环。 (请参阅之前的问题此处和此处)。
我想知道(以及我在前面的问题中没有看到答案)是为什么 C# 编译器没有捕获这个错误? 它检查其他类型的循环引用(从自身继承的类等),对吧? 难道只是这个错误不够常见,不值得检查吗? 或者是否有某种我没有想到的情况,当您希望属性以这种方式实际引用自身时?
您可以在最后评论中看到“官方”原因这里。
Microsoft 于 2008 年 11 月 14 日发布于 19:52
感谢您的建议 视觉工作室!
你是对的,我们可以轻松地 检测属性递归,但我们 不能保证没有任何事 有用的实现是由 递归。财产的主体 可以在您的对象上设置其他字段 这会改变下一个的行为 递归,可以改变其行为 基于控制台的用户输入, 或者甚至可以基于不同的行为 关于随机值。在这些情况下, 自递归性质确实可以 终止递归,但我们有 无法确定情况是否如此 在编译时(没有解决 停止问题!)。
由于上述原因(以及 需要进行重大改变 不允许这样做),我们将无法 禁止自递归性质。
亚历克斯·特纳
项目经理
Visual C# 编译器
除了 Alex 的解释之外的另一点是,我们尝试对执行您可能不希望执行的操作的代码发出警告,这样您可能会意外地携带错误。
在这种特殊情况下,警告实际上可以为您节省多少时间?单次测试运行。当你测试代码的时候你就会发现这个错误,因为它总是立即崩溃并可怕地死掉。该警告实际上不会给您带来太多好处。 递归属性评估中存在一些“微妙”错误的可能性很低。 相比之下,如果您执行以下操作,我们
会发出警告:
int customerId;
...
this.customerId= this.customerId;
没有可怕的崩溃和死机,并且代码是有效的代码;它为一个字段分配一个值。但由于这是无意义的代码,因此您可能无意这样做。因为它不会可怕地死去,所以我们发出警告,这里有一些你可能无意的东西,也可能不会通过崩溃发现。
int count = 0;
public string Abc
{
count++;
if (count < 1) return Abc;
return "Foo";
}
上面是一个虚拟示例,但我确信人们可以想出类似的有用的递归代码。编译器无法确定是否会发生无限递归(停止问题)。
在简单的情况下生成警告会很有帮助。
当您第一次致电该酒店时,您会很容易发现这个拼写错误。
abc
。
其次,只要不是无限递归,递归并没有什么不好。例如,代码可能会调整一些内部变量,然后递归地调用相同的 getter。然而,对于编译器来说,根本没有简单的方法来证明某些递归是否是无限的(任务至少是 NP)。编译器可以捕获一些简单的情况,但是消费者会惊讶地发现更复杂的情况通过了编译器的检查。
但是,有意创建有用的递归属性(使用
if
语句)是可能的,尽管不太可能。