为什么 C# 编译器不阻止属性引用自身?

问题描述 投票:0回答:6

如果我这样做,我会得到一个

System.StackOverflowException

private string abc = "";
public string Abc
{
    get
    { 
        return Abc; // Note the mistaken capitalization
    }
}

我明白为什么——属性引用自身,导致无限循环。 (请参阅之前的问题此处此处)。

我想知道(以及我在前面的问题中没有看到答案)是为什么 C# 编译器没有捕获这个错误? 它检查其他类型的循环引用(从自身继承的类等),对吧? 难道只是这个错误不够常见,不值得检查吗? 或者是否有某种我没有想到的情况,当您希望属性以这种方式实际引用自身时?

c# exception
6个回答
46
投票

您可以在最后评论中看到“官方”原因这里

Microsoft 于 2008 年 11 月 14 日发布于 19:52

感谢您的建议 视觉工作室!

你是对的,我们可以轻松地 检测属性递归,但我们 不能保证没有任何事 有用的实现是由 递归。财产的主体 可以在您的对象上设置其他字段 这会改变下一个的行为 递归,可以改变其行为 基于控制台的用户输入, 或者甚至可以基于不同的行为 关于随机值。在这些情况下, 自递归性质确实可以 终止递归,但我们有 无法确定情况是否如此 在编译时(没有解决 停止问题!)。

由于上述原因(以及 需要进行重大改变 不允许这样做),我们将无法 禁止自递归性质。

亚历克斯·特纳

项目经理

Visual C# 编译器


14
投票

除了 Alex 的解释之外的另一点是,我们尝试对执行您可能不希望执行的操作的代码发出警告,这样您可能会意外地携带错误

在这种特殊情况下,警告实际上可以为您节省多少时间?单次测试运行。当你测试代码的时候你就会发现这个错误,因为它总是立即崩溃并可怕地死掉。该警告实际上不会给您带来太多好处。 递归属性评估中存在一些“微妙”错误的可能性很低。 相比之下,如果您执行以下操作,我们

发出警告: int customerId; ... this.customerId= this.customerId;

没有可怕的崩溃和死机,并且代码是有效的代码;它为一个字段分配一个值。但由于这是无意义的代码,因此您可能无意这样做。因为它不会可怕地死去,所以我们发出警告,这里有一些你可能无意的东西,也可能不会通过崩溃发现。


10
投票

int count = 0; public string Abc { count++; if (count < 1) return Abc; return "Foo"; }

上面是一个虚拟示例,但我确信人们可以想出类似的有用的递归代码。编译器无法确定是否会发生无限递归(停止问题)。

在简单的情况下生成警告会很有帮助。


1
投票

当您第一次致电该酒店时,您会很容易发现这个拼写错误。


1
投票
abc


其次,只要不是无限递归,递归并没有什么不好。例如,代码可能会调整一些内部变量,然后递归地调用相同的 getter。然而,对于编译器来说,根本没有简单的方法来证明某些递归是否是无限的(任务至少是 NP)。编译器可以捕获一些简单的情况,但是消费者会惊讶地发现更复杂的情况通过了编译器的检查。


0
投票
此外,所有这些情况(甚至递归构造函数)都肯定会失败。


但是,有意创建有用的递归属性(使用

if

语句)是可能的,尽管不太可能。

    

© www.soinside.com 2019 - 2024. All rights reserved.