C# - 属性导致StackOverflow

时间:2012-08-22 20:38:24

标签: c# stack-overflow

public class ModelInfo
{
    public int AssignedCount { get; set; }
    public int UnassignedCount { get; set; }
    public int TotalCount { get { return UnassignedCount + TotalCount; } }
}

*的 编辑: * 我意识到当我把这个代码放在SO中时,TotalCount属性正在添加UnassignedCount + TotalCount(我的意思是将其他两个计数加在一起)。有人可以提供一个足够的解释为什么SO错误发生?我的意思是,低级别的东西。

Stackoverflowing!

9 个答案:

答案 0 :(得分:13)

您正在TotalCount内拨打TotalCount,请勿这样做。

您可以为该属性的值设置另一个字段。

尽管如此,我怀疑你的代码应该是:

public int TotalCount { get { return UnassignedCount + AssignedCount ; } }

编辑: 至于堆栈溢出发生的原因,那是因为当你使用Properties时,.NET编译器实际上会生成2个函数,set_PropertyNameget_PropertyName。所以在本质上,它会导致get_PropertyName方法调用的堆栈溢出变得无限深。

答案 1 :(得分:4)

查看正在发生的事情(IMO)的最简单方法是将这些属性转换为方法:

// If we didn't have properties, this is what the two first lines would be. Ick!
private int assignedCount;
private int unassignedCount;

public int GetAssignedCount()
{
    return assignedCount;
}

public void SetAssignedCount(int value)
{
    assignedCount = value;
}

public int GetUnassignedCount()
{
    return unassignedCount;
}

public void SetUnassignedCount(int value)
{
    unssignedCount = value;
}

// And here's the read-only TotalCount property translation
public int GetTotalCount()
{
    return GetUnassignedCount() + GetTotalCount();
}

现在GetTotalCount()内的递归应该非常清楚。该方法无条件地调用自身,因此最终会炸毁堆栈。

自动实现属性的混合以及属性访问外观这样的事实有时会妨碍记住它们实际上只是伪装的方法。希望上面的翻译更加明显。

答案 2 :(得分:3)

  

有人可以提供一个足够的解释,说明为什么会出现SO错误吗?

当然:为了计算TotalCount,编译器会生成如下代码:

  • 获取UnassignedCount
  • 获取TotalCount
  • UnassignedCount添加到TotalCount
  • 返回结果

调用TotalCount的属性getter时(记住,getter是一个使用特殊语法的常规无参数函数),运行时将返回地址放在堆栈上。第二步在开始时找回我们,在堆栈上有一个额外的返回地址;第三步再做一次,然后是第四步,第五步,依此类推。每次调用都会在堆栈上存放另一个返回地址。这一直持续到堆栈的极限,此时抛出异常。

答案 3 :(得分:2)

你应该写下这个: 您应该注意,TotalCount永远不能设置为没有值。您是否意味着这样做:

public class ModelInfo
{
    public int AssignedCount { get; set; }
    public int UnassignedCount { get; set; }
    public int TotalCount { get { return UnassignedCount + AssignedCount; } }
}

答案 4 :(得分:1)

有一种称为“堆栈”的机制,用于跟踪嵌套调用。当您调用方法或函数时,当前的“堆栈帧”(控件将在您调用的方法返回时转移到的地址,以及方法中的任何参数和方法本地)被压入堆栈。当控制返回到您的方法时,弹出此堆栈帧并将CPU寄存器恢复到其先前状态,以便您的方法可以继续执行。

堆栈是一个固定的内存分配,因此在用完地方存储恢复CPU寄存器状态所需的信息之前,只能调用这么多级别。当你的函数返回时。此时,发生堆栈溢出错误,因为您溢出堆栈。您进行了如此多的嵌套调用,但是内存不足以将其记录下来。

这就是异常发生的原因。你无限递归:你的属性getter一遍又一遍地调用自己,直到堆栈上没有空间为止。

答案 5 :(得分:0)

因为您指的是TotalCount getter中的TotalCount。发生无限循环,直到达到堆栈溢出。

答案 6 :(得分:0)

在尝试获取TotalCount

的值时,您正在循环

粗略地说,获得TotalCount的逻辑是:

  • 获取UnassignedCount的值
  • 获取Totalcount的价值

重复,冲洗并洗净。

编辑:至于原因,请查看Wiki

答案 7 :(得分:0)

你是一个无限递归,一个自称为

的属性

答案 8 :(得分:0)

因为调用堆栈(理论上)会无限深入。并且您没有无限堆栈来保存您需要的所有数据。