为什么';C#编译器不能阻止属性引用它们自己吗?

为什么';C#编译器不能阻止属性引用它们自己吗?,c#,compiler-construction,exception,C#,Compiler Construction,Exception,如果我这样做,我会得到一个System.StackOverflowException: private string abc = ""; public string Abc { get { return Abc; // Note the mistaken capitalization } } 我理解为什么--属性正在引用自身,导致无限循环。(见前面的问题和) 我想知道的是(我在前面的问题中没有看到答案)为什么C#编译器没有发现这个错误?它检查其他类型的

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

private string abc = "";
public string Abc
{
    get
    { 
        return Abc; // Note the mistaken capitalization
    }
}
我理解为什么--属性正在引用自身,导致无限循环。(见前面的问题和)


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

他们可能认为这样做将不必要地使编译器复杂化,而不会带来任何实际收益

第一次调用此属性时,您将很容易发现此键入错误

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

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

谢谢你的建议 Visual Studio

你说得对,我们很容易 检测属性递归,但我们 不能保证什么都没有 由 递归。财产的主体 无法在对象上设置其他字段 这会改变下一代的行为 递归可能会改变其行为 根据来自控制台的用户输入, 或者甚至可以根据具体情况做出不同的行为 关于随机值。在这些情况下 自递归属性确实可以 终止递归,但我们必须 没有办法确定情况是否如此 在编译时(不解决 停止问题!)

基于上述原因(以及 打破它需要的改变 不允许这样),我们就不能 禁止自递归属性

亚历克斯·特纳

项目经理

Visual C#编译器


它检查的其他情况(递归构造函数除外)无效。
此外,所有这些情况(甚至递归构造函数)都可以保证失败


但是,有可能(尽管可能性不大)有意创建一个有用的递归属性(使用
if
语句)。

属性引用自身并不总是导致无限递归和堆栈溢出。例如,这很好:

int count = 0;
public string Abc
{
    count++;
    if (count < 1) return Abc;
    return "Foo";
}
int count=0;
公共字符串Abc
{
计数++;
如果(计数<1)返回Abc;
返回“Foo”;
}
上面是一个虚构的例子,但我相信有人会想出类似的有用的递归代码。编译器无法确定是否会发生无限递归(停止问题)


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

首先,您将得到一个未使用变量的警告
abc


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

除了Alex的解释之外,还有一点是,我们试图对代码发出警告,这些代码可能做了您可能不想做的事情,这样,您可能会意外地附带此bug

在这种特殊情况下,警告实际能为您节省多少时间?一次测试运行。在测试代码的那一刻,您就会发现这个bug,因为它总是立即崩溃并可怕地死去。这个警告实际上不会给你带来什么好处。递归属性评估中存在一些细微缺陷的可能性很低

相反,如果您这样做,我们会发出警告:

int customerId; 
...
this.customerId= this.customerId;

没有可怕的崩溃和死亡,代码是有效代码;它为字段指定一个值。但由于这是一个荒谬的代码,你可能不是有意这么做的。因为它不会可怕地死去,所以我们给出一个警告,这里有一些东西你可能并不打算,也可能不会通过崩溃发现。

通过“引用自身”,我想我真的是想说“递归调用自身”,但你明白了。不过,如果他们制作了一个关于它的编译器警告,那可能会更好。我认为这会很有价值。有道理。可以肯定地说,故意做一个递归属性getter可能永远都不是一个好主意,因为它只有在有副作用的情况下才会停止,而且(如果我理解正确的话)在有副作用的情况下,方法比属性更受欢迎?@Tim:这些副作用可能是通常情况下的内部副作用,用户看不见的副作用。属性getter产生副作用并非完全不可能(例如,如果您想计算调用get的次数)。好吧,这仍然很愚蠢:)@Nick很多商店都非常严格地要求不允许任何东西编译时带有警告,所以他们非常严格地要求为可能不需要的东西生成警告。请参阅@Tanzelax-True,但我发现您引用的链接中的示例很奇怪,因为他们明确提到“无用代码”不值得警告,但如果您创建一个从未分配给的成员变量foo,他们会产生一个警告“字段foo从未使用过”。我在Alex回答中讨论了这个问题。你所说的“但既然这是无意义的代码,你可能不是有意这么做的。既然它不会可怕地死去,我们就发出警告,这里有些东西你可能不是有意的”似乎与你在这里的博客帖子相矛盾:@Nick:我没有看到矛盾。(这并不意味着没有一个:我很大,我包含很多。)我只是不明白你的意思。@Eric Lippert:谢谢你推荐我自己的歌曲。:-)谢谢你和answe