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

Tim*_*man 35 c# compiler-construction exception

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

private string abc = "";
public string Abc
{
    get
    { 
        return Abc; // Note the mistaken capitalization
    }
}
Run Code Online (Sandbox Code Playgroud)

我理解为什么 - 属性引用自身,导致无限循环.(在此处此处查看以前的问题).

我想知道的(以及我之前没有看到的问题)是为什么C#编译器没有抓住这个错误?它检查一些其他类型的循环引用(继承自己的类等),对吗?只是这个错误不常见,值得检查吗?或者是否有一些我没有想到的情况,当你想要一个房产以这种方式实际引用自己的时候?

Bra*_*don 44

您可以在此处的最后一条评论中看到"官方"原因.

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

感谢您对Visual Studio的建议!

你是对的,我们可以很容易地检测属性递归,但我们不能保证递归没有任何有用的东西.属性的主体可以设置对象上的其他字段,这些字段会更改下一个递归的行为,可以根据来自控制台的用户输入更改其行为,或者甚至可以根据随机值进行不同的操作.在这些情况下,自递归属性确实可以终止递归,但我们无法确定在编译时是否就是这种情况(没有解决暂停问题!).

由于上述原因(以及不允许这样做的重大变化),我们无法禁止自递归属性.

亚历克斯特纳

项目经理

Visual C#编译器

  • 如果它们产生编译器警告它可能会很好.我认为这很有价值. (20认同)
  • @Nick许多商店非常严格,不允许任何东西编译警告,所以他们非常严格地为可能不需要的东西发出警告.请参阅http://blogs.msdn.com/ericlippert/archive/2010/01/25/why-are-unused-using-directives-not-a-warning.aspx (3认同)

Eri*_*ert 13

除了Alex的解释之外,另一点是我们试图给代码做警告,这些代码执行了一些您可能不想要的事情,这样您就可能意外地发现了这个bug.

在这种特殊情况下,警告实际上会节省多少时间?单次测试运行.你在测试代码的那一刻就会发现这个bug,因为它总是会立即崩溃并且死得很厉害.这个警告实际上并没有给你带来太大的好处.在递归属性评估中存在一些微妙错误的可能性很低.

相比之下,如果您执行以下操作,我们发出警告:

int customerId; 
...
this.customerId= this.customerId;
Run Code Online (Sandbox Code Playgroud)

没有可怕的崩溃和死亡,代码是有效的代码; 它为一个字段赋值.但由于这是无意义的代码,你可能并不是故意这样做.因为它不会死得很厉害,所以我们会发出一个警告:这里有一些你可能不想要的东西,否则可能不会通过崩溃发现.

  • @Nick:两种情况之间的区别在于,在“未使用的使用”示例中,未使用的使用可能只是绒毛。它没有任何意义,也从未打算具有意义,可以在不进行语义更改的情况下将其删除或保留。“将变量分配给自己”警告几乎可以肯定是*打算说别的*。我们不仅指出该代码是无用的,而且还指出该代码*可能是有目的的,但实际上是无用的*,两者的组合很可能是一个错误。 (2认同)

dbk*_*bkk 10

引用自身的属性并不总是导致无限递归和堆栈溢出.例如,这工作正常:

int count = 0;
public string Abc
{
    count++;
    if (count < 1) return Abc;
    return "Foo";
}
Run Code Online (Sandbox Code Playgroud)

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

在简单的情况下生成警告将是有帮助的.