为什么这个按钮对象会导致堆栈溢出?

时间:2021-05-30 15:14:55

标签: c#

 void OpenClean( int i, int j) {

        bnt[i, j] = new Button();
        if (!bnt[i,j].Enabled) return;

        bnt[i, j].Enabled = false;
        bnt[i,j].BackColor = Color.Aquamarine;
        bnt[i, j].Text = data[i, j].ToString();
        if (data[i, j] == 0) {

            if (i > 0 && j > 0 && data[i - 1, j - 1] == 0) OpenClean(i - 1, j - 1);
            if (i > 0 && data[i - 1, j] == 0) OpenClean(i - 1, j);
            if (i > 0 && j < 8 && data[i - 1, j + 1] == 0) OpenClean(i - 1, j + 1);
            if (j > 0 && data[i, j - 1] == 0) OpenClean(i, j - 1);
            if (j < 8 && data[i, j + 1] == 0) OpenClean(i, j + 1);
            if (i < 8 && j > 0 && data[i + 1, j - 1] == 0) OpenClean(i + 1, j - 1);
            if (i < 8 && data[i + 1, j] == 0) OpenClean(i + 1, j);
            if (i < 8 && j < 8 && data[i + 1, j + 1] == 0) OpenClean(i + 1, j + 1);
        }

它告诉我进程因 StackOverflowException 而终止。 由于我的经验有限,我没有找到有效的方法。 这个问题困扰我很久了。 请帮助或尝试给我一些解决方法的想法。

提前致谢!

1 个答案:

答案 0 :(得分:0)

您从未将 data[i, j] 设置为除 0 以外的值。因此,递归永远不会停止。您必须将检查的单元格设置为不同的值,以便它们不会被一次又一次地检查...

您还可以使用 bnt[i, j] = new Button(); 创建一个新按钮,而不是检查现有按钮。因此,您永远不会看到带有 Enabled == false 的按钮,因为 default value for Enabled is true

最好将逻辑基于模型(即 data[,]),并将 UI(控件)仅用于显示。

const int Inspected = -1;
void OpenClean( int i, int j) {
    ...
    if (data[i, j] == 0) {
        data[i, j] = Inspected; // <====== This stops the endless recursion!
        if (i > 0 && j > 0 && data[i - 1, j - 1] == 0) OpenClean(i - 1, j - 1);
        ...
    }
}

顺便说一句,您正在测试 0 两次。在再次调用 OpenClean 和内部 OpenClean 之前。只做一次。

void OpenClean( int i, int j) {
    if (data[i, j] == 0) { // This one does the job.
        data[i, j] = Inspected; // <======
        // bnt[i, j] = new Button();  <=== drop this!
        // if (!bnt[i,j].Enabled) return;  <=== drop this! We test data instead.

        bnt[i, j].Enabled = false;
        bnt[i,j].BackColor = Color.Aquamarine;
        bnt[i, j].Text = data[i, j].ToString();

        if (i > 0 && j > 0) OpenClean(i - 1, j - 1);
        if (i > 0         ) OpenClean(i - 1, j);
        if (i > 0 && j < 8) OpenClean(i - 1, j + 1);
        if (         j > 0) OpenClean(i,     j - 1);
        if (         j < 8) OpenClean(i,     j + 1);
        if (i < 8 && j > 0) OpenClean(i + 1, j - 1);
        if (i < 8         ) OpenClean(i + 1, j);
        if (i < 8 && j < 8) OpenClean(i + 1, j + 1);
    }
}

如果在OpenClean开头做范围测试,可以去掉所有其他范围测试。

void OpenClean( int i, int j) {
    if (i > 0 && i < 8 && j > 0 && j < 8 && data[i, j] == 0) { // This one does the job.
        data[i, j] = Inspected; // <======

        bnt[i, j].Enabled = false;
        bnt[i,j].BackColor = Color.Aquamarine;
        bnt[i, j].Text = data[i, j].ToString();

        OpenClean(i - 1, j - 1);
        OpenClean(i - 1, j);
        OpenClean(i - 1, j + 1);
        OpenClean(i,     j - 1);
        OpenClean(i,     j + 1);
        OpenClean(i + 1, j - 1);
        OpenClean(i + 1, j);
        OpenClean(i + 1, j + 1);
    }
}

使用 C# 9.0 模式,您可以稍微简化条件

if (i is > 0 and < 8 && j is > 0 and < 8 && data[i, j] == 0)
相关问题