C#数字猜测游戏问题

3

我一直遇到堆栈溢出错误(开个玩笑):“未处理的类型为'System.StackOverflowException'的异常在NumberGuessingGame.exe中发生”

我猜如果您看到我的代码以及它发生的位置会更有帮助:

源代码 - testClass:

namespace NumberGuessingGame_08029490
{
public class testClass : Form1
{
    public bool _gameWon;
    public bool _gameRunning;
    public int _number;
    public int _guessesRemaining;

    public int guessesRemaining
    {
        get { return _guessesRemaining; }
    }

    public bool gameEnded
    {
        get { return !_gameRunning; }
    }

    public bool gameWon
    {
        get { return _gameWon; }
    }
    public testClass()
    {
        _gameRunning = false;
        _gameWon = false;
    }

    public void saveNewTestGame(int numberGuesses)
    {

        if (numberGuessesComboBox.SelectedIndex == 0)
        {
            numberGuesses = 1;
        }
        if (numberGuessesComboBox.SelectedIndex == 1)
        {
            numberGuesses = 3;
        }
        if (numberGuessesComboBox.SelectedIndex == 2)
        {
            numberGuesses = 5;
        }

        _guessesRemaining = numberGuesses;
        _gameRunning = true;
    }

    public bool makeGuess(int guessNumber)
    {
        if (_gameRunning)
        {
            _guessesRemaining--;
            if (_guessesRemaining <= 0)
            {
                _gameWon = false;
                _gameRunning = false;
                return false;


            }
            if (guessNumber == _number)
            {
                _gameWon = true;
                return true;
            }
            if (guessNumber > _number)
            {
                guessResultTextBox.Text = "Your Guess is too high, try again";
                _gameWon = false;
                return false;
            }
            if (guessNumber < _number)
            {
                guessResultTextBox.Text = "Your Guess is too low, try again";
                _gameWon = false;
                return false;
            }
            else
            {
                return false;
            }
        }

        else
        {
            throw new Exception("The game is not running. Call newGame() before making a guess.");

        }

    }
}
}

来源 - 游戏类:

namespace NumberGuessingGame_08029490
{
public class gameClass : Form1
{

    public bool _gameWon;
    public bool _gameRunning;
    public static Random randomNum = new Random();
    public int _number;
    public int _guessesRemaining;

    public int guessesRemaining
    {
        get { return _guessesRemaining; }
    }

    public bool gameEnded
    {
        get { return !_gameRunning; }
    }

    public bool gameWon
    {
        get { return _gameWon; }
    }

    public gameClass()
    {
        _gameRunning = false;
        _gameWon = false;
    }
    public void saveNewGame(int numberGuesses)
    {

        if (numberGuessesComboBox.SelectedIndex == 0)
        {
            numberGuesses = 1;
        }
        if (numberGuessesComboBox.SelectedIndex == 1)
        {
            numberGuesses = 3;
        }
        if (numberGuessesComboBox.SelectedIndex == 2)
        {
            numberGuesses = 5;
        }
        if (rangeNumbersComboBox.SelectedIndex == 0)
        {
            int randomNumFive = randomNum.Next(1, 5);
            randomNumFive = _number;
        }
        if (rangeNumbersComboBox.SelectedIndex == 1)
        {
            int randomNumTen = randomNum.Next(1, 10);
            randomNumTen = _number;
        }
        if (rangeNumbersComboBox.SelectedIndex == 2)
        {
            int randomNumTwenty = randomNum.Next(1, 20);
            randomNumTwenty = _number;
        }
        _guessesRemaining = numberGuesses;
        _gameRunning = true;
    }

    public bool makeGuess(int guessNumber)
    {
        if (_gameRunning)
        {
            _guessesRemaining--;
            if (_guessesRemaining <= 0)
            {
                _gameWon = false;
                _gameRunning = false;
                return false;

            }
            if (guessNumber == _number)
            {
                _gameWon = true;
                return true;
            }
            if (guessNumber > _number)
            {
                guessResultTextBox.Text = "Your Guess is too high, try again";
                _gameWon = false;
                return false;
            }
            if (guessNumber < _number)
            {
                guessResultTextBox.Text = "Your Guess is too low, try again";
                _gameWon = false;
                return false;
            }
            else
            {
                return false;
            }

        }

        else
        {
            throw new Exception("The game is not running. Call newGame() before making a guess.");

        }

    }
}
}

来源 - 表单1:

namespace NumberGuessingGame_08029490
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

    }

    testClass newTest = new testClass();
    gameClass newGame = new gameClass();


    private void saveButton_Click(object sender, EventArgs e)
    {

        if (testCheckBox.Checked == true)
        {
            int numberGuesses = Convert.ToInt32(numberGuessesComboBox.SelectedIndex);
            int _number = Convert.ToInt32(testNumberTextBox.Text);

            newTest.saveNewTestGame(numberGuesses);

        }
        if (testCheckBox.Checked == false)
        {
            int numberGuesses = Convert.ToInt32(numberGuessesComboBox.SelectedIndex);
            int _number = Convert.ToInt32(rangeNumbersComboBox.SelectedIndex);

            newGame.saveNewGame(numberGuesses);
        }

    }

    private void guessButton_Click(object sender, EventArgs e)
    {

        if (testCheckBox.Checked == true)
        {
            int guessNumber = Convert.ToInt32(guessNumberTextBox.Text);
            bool correctAnswer = newTest.makeGuess(guessNumber);

            if (correctAnswer)
            {
                MessageBox.Show("Weldone, you Won!!");
            }

            // if (game.GameEnded)
            //  {
            // disable guess button, show loss label
            //  }
        }
        if (testCheckBox.Checked == false)
        {
            int guessNumber = Convert.ToInt32(guessNumberTextBox.Text);
            bool correctAnswer = newGame.makeGuess(guessNumber);

            if (correctAnswer)
            {
                MessageBox.Show("Weldone, you Won!!");
            }

            // if (game.GameEnded)
            //  {
            // disable guess button, show loss label
            //  }
        }
    }

}
}

编辑:不再出现StackOverflowException, 代码错误:

感谢大家的帮助 <3

已将顶部的"表单1"移除,目前似乎已解决问题,但由于组合框、文本框变量不再继承,无法在代码中使用它们,因此无法测试解决方案。有什么想法可以让它们被使用吗?

Error   1   The name 'numberGuessesComboBox' does not exist in the current context  E:\Projects\NumberGuessingGame\NumberGuessingGame\testClass.cs  46  17  NumberGuessingGame

Error   7   The name 'rangeNumbersComboBox' does not exist in the current context   E:\Projects\NumberGuessingGame_08029490\NumberGuessingGame_08029490\gameClass.cs    58  17  NumberGuessingGame_08029490

Error   10  The name 'guessResultTextBox' does not exist in the current context E:\Projects\NumberGuessingGame_08029490\NumberGuessingGame_08029490\testClass.cs    84  21  NumberGuessingGame_08029490

你能设置一个断点并找出它在哪里崩溃吗? - JonH
这不可能是全部的代码... - JonH
4个回答

4

栈溢出几乎总是由于无限递归引起的。换句话说,一个函数在循环中不断地调用自身,没有跳出这个循环,所以它会被调用无数次,直到堆栈溢出。有时候,函数A调用函数B,而函数B又调用函数A,但其效果是相同的。搜索代码找到这个循环,或查看调试器提供的堆栈跟踪,看看循环是什么。

编辑:我浏览了您发布的代码,但没有找到问题所在。您采取什么操作来获取错误?是在点击按钮后立即出现,还是在加载程序时,或其他情况下?

编辑2:您从Form1继承您的实用类可能是不正确的,也可能与此有关:

public class testClass : Form1

几乎可以肯定应该只是
public class testClass

编辑3(回答原帖中编辑的新问题):要测试Form1,您的testClass类可以有一个类型为Form1的成员变量,并通过Form1的公共方法和属性进行测试。Form1甚至可以创建testClass实例(尽管这被认为是不好的做法),并将自身传递给testClass的构造函数:

// Inside Form1()
private TestClass m_testClass;

Form1()
{
    m_testClass = new testClass(this);
    ....
}

// Inside testClass
private Form1 m_testForm;

testClass(Form1 formToTest)
{
    m_testForm = formToTest;
}

void DoTest()
{
    // use m_testForm here...
}

错误发生在我调试时,但我查看了堆栈跟踪,它发生在form1代码中的testClass newTest = new testClass();和testclass代码中的public testClass()。如果我删除newTest = new testClass();,下一行gameClass newGame = new gameClass();将出现相同的问题。:/ - Samantha Silva

1

虽然与您的StackOverflow异常无关,但以下是一些改进代码的一般注意事项:

  1. 为什么要使用所有SelectedIndex if语句,而不使用SelectedValue?
  2. 尝试使用else if语句。如果SelIndex == 0,则检查SelIndex == 1是无用的。
  3. 我可以建议从大写字母开始编写类和属性吗?
  4. 尝试隔离重复的代码(将其放入单独的方法中或...)
  5. 对于常规布尔值,请使用(变量)和(!变量)而不是(变量== true)或(变量== false)
  6. 布尔值已经初始化为false

编辑:Form1继承导致无限循环(因此出现StackOverflowException)

Form1类有两个字段:testClass和gameClass。
但是testClass和gameClass都继承自Form1。
因此,每个testClass都有两个字段:testClass和gameClass。
每个gameClass也都有两个字段:testClass和gameClass。

看到其中的循环了吗?

很抱歉要说,但请阅读一些C#原则和面向对象编程,因为这看起来有点像你不知道在做什么。我并不是为了打击你的积极性而说这话,但当你理解代码背后的概念时,它会更容易且更有趣。

谢谢您的建议,我一定会考虑的。我对C#还很陌生。 - Samantha Silva
1
@Samantha:你的代码无法编译,因为你正在从另一个类引用窗体控件。抱歉我们不能帮助你完成整个应用程序 ;) - Yvo

0

你的构造函数中存在无限递归。

从你的testClassgameClass中去掉: Form1

因为它们都继承自Form1,所以每个类都会实例化另一个testClass+gameClass的副本,这是由以下代码行引起的:

testClass newTest = new testClass();
gameClass newGame = new gameClass();

编辑:为了清楚起见,这里发生的情况是:testClass 和 gameClass 通过继承 Form1,也继承了所有成员变量,包括成员 newText 和 newGame。从 C# 字段的 MSDN 文章 中可以看到:“可以在声明字段时使用赋值运算符给字段赋初始值...字段会在调用对象实例的构造函数之前立即初始化。”

因此,当一个新的 Form1 被实例化时,它首先尝试为其 newTest 和 newGame 成员分配初始值。

在创建新的 testClass 时,在 testClass 到达其构造函数之前,它将尝试为其自己的 newTest 和 newGame 成员提供初始值。

重复以上步骤,直到堆栈溢出。


我认为你可能是对的,我需要编辑我的组合框和文本框,因为由于它没有继承,所以它不再在类中接受它们,因此在测试是否有效之前,我必须先编辑它。 - Samantha Silva
@JonH:我在47分钟前回答了你的问题(如果我算相对时间没错的话,那就是比你早7分钟。:) - Scott Stafford
@JonH和@Scott Stafford:你们两个都没有提到为什么会发生堆栈溢出,只是提到了解决方法。 - Tanzelax
-1 @ Tanzelax,否定我真的很不好,尤其是考虑到你采纳了我的答案。 - JonH
我没有给你打-1分,只是发表了评论。除了这篇帖子中的--那个人,我没有给其他任何人打-1分,因为你提供了正确的答案。 - Tanzelax
@Tanzelax:确实如此,+1. ;) - Scott Stafford

0
  1. 你的代码中没有循环,所以我排除了递归问题或者是无限循环的问题。
  2. 一开始我以为你漏掉了主函数,但后来意识到这是一个窗体应用程序(所以忽略顶部的注释)。
  3. 你为什么要声明一个类,然后继承该类的窗体?此外:

    public class testClass : Form1

既然只是一个类,那就把: Form1去掉。


当我移除继承后,它不再允许我在类上使用表单的某些部分,比如组合框和一些文本框。 - Samantha Silva
@Samantha,Form1需要从你的类模块测试类和游戏类中移除。 - JonH
尽管摆脱Form1解决了问题,但这是一个递归问题-只不过不是典型的递归问题。 - Tanzelax
@Tanzelax - 你无缘无故地否定我,这让我很失望。我所描述的问题是从原始帖子中开始的,没有循环引起递归问题。然后你对此进行否定是相当糟糕的。 - JonH
我没有给你打负分,我只是指出这是一个递归问题,因为你提到了你“排除了它是一个递归问题”。 - Tanzelax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接