【问题标题】:C#/WPF Error: An Unhandled Exception of Type 'System.StackOverflow Exception' Occured (Tic-Tac-Toe)C#/WPF 错误:发生“System.StackOverflow 异常”类型的未处理异常(井字游戏)
【发布时间】:2016-06-19 06:44:55
【问题描述】:

我对 C# 和 WPF 非常陌生,所以请耐心等待。我正在做一个 C#/WPF 井字游戏。游戏开始并进行了一些动作后,我不断收到以下错误,我不知道为什么:

“'System.StackOverflow 异常'类型的未处理异常”

就计算机而言,不必有任何策略。所以,我想要代码做的就是随机选择谁先走(计算机或人类),当轮到计算机时,计算机应该随机选择一个启用的按钮,并分配一个“X”或一个“O”给它。任何帮助将不胜感激。

另外,如果有更简单或更短的编码方式,请务必告诉我!正如我所说,我对这一切都很陌生。

注意:我还没有想出一个函数/方法来确定谁是获胜者。我不需要帮助。

***** 编辑:按照建议,我在“MainWindow”类中声明并实例化了一次“rnd”,并在“randomSquare”方法中留下了“rnd.Next”。以前,它在游戏的许多不同点上到处乱扔错误。现在,它只在人类先走并且是第 9 步时抛出错误。对于如何解决这个问题,有任何的建议吗?下面是我编辑的代码。*****

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Operation6
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        bool player1 = true;
        int playerNumber;
        Random rnd1 = new Random();
        Random rnd2 = new Random();    /// Edit: Instantiated only once.

        public MainWindow()
        {
            InitializeComponent();

            playerNumber = rnd1.Next(1, 3);

            if (playerNumber == 1)
                computer();
        }

        private int randomSquare()
        {
            int number;

            number = rnd2.Next(1, 10);

            return number;
        }

        private void computer()
        {
            int squareNumber = randomSquare();

            if (squareNumber == 1 && square1.IsEnabled == true)
            {
                if (player1)
                    square1.Content = "X";
                else
                    square1.Content = "O";

                square1.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 1 && square1.IsEnabled == false)
                computer();
            else if (squareNumber == 2 && square2.IsEnabled == true)
            {
                if (player1)
                    square2.Content = "X";
                else
                    square2.Content = "O";

                square2.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 2 && square2.IsEnabled == false)
                computer();
            else if (squareNumber == 3 && square3.IsEnabled == true)
            {
                if (player1)
                    square3.Content = "X";
                else
                    square3.Content = "O";

                square3.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 3 && square3.IsEnabled == false)
                computer();
            else if (squareNumber == 4 && square4.IsEnabled == true)
            {
                if (player1)
                    square4.Content = "X";
                else
                    square4.Content = "O";

                square4.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 4 && square4.IsEnabled == false)
                computer();
            else if (squareNumber == 5 && square5.IsEnabled == true)
            {
                if (player1)
                    square5.Content = "X";
                else
                    square5.Content = "O";

                square5.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 5 && square5.IsEnabled == false)
                computer();
            else if (squareNumber == 6 && square6.IsEnabled == true)
            {
                if (player1)
                    square6.Content = "X";
                else
                    square6.Content = "O";

                square6.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 6 && square6.IsEnabled == false)
                computer();
            else if (squareNumber == 7 && square7.IsEnabled == true)
            {
                if (player1)
                    square7.Content = "X";
                else
                    square7.Content = "O";

                square7.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 7 && square7.IsEnabled == false)
                computer();
            else if (squareNumber == 8 && square8.IsEnabled == true)
            {
                if (player1)
                    square8.Content = "X";
                else
                    square8.Content = "O";

                square8.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 8 && square8.IsEnabled == false)
                computer();
            else if (squareNumber == 9 && square9.IsEnabled == true)
            {
                if (player1)
                    square9.Content = "X";
                else
                    square9.Content = "O";

                square9.IsEnabled = false;
                player1 = !player1;
            }
            else if (squareNumber == 9 && square9.IsEnabled == false)
                computer();
            else
                draw();
        }

        private void draw()
        {
            textBlock1.Text = "It's a tie!";
        }

        private void squareClick(object sender, RoutedEventArgs e)
        {
            Button square = (Button)sender;

            if (player1)
                square.Content= "X";
            else
                square.Content = "O";

            square.IsEnabled = false;
            player1 = !player1;
            computer();
        }
    }
}

【问题讨论】:

  • 为什么不用调试器跟踪代码并找到无限循环呢?有多难?
  • @Ian 如果调试是基于由于重复随机种子而导致的重复随机数,则很有可能不会发生这种情况。
  • 异常没有堆栈跟踪吗?
  • 我认为 Avner Shahar-Kashtan 的回答可能是正确的。我认为人们应该提供一个拒绝投票的理由,并且不应该是匿名的。
  • 1.不要在每次需要随机数时实例化 Random 对象。使用私有字段(就像player1 字段)。 2.不要使用递归,这里不需要,混淆和你溢出的可能原因。使用某种while 循环根据需要重试或找出仅在空闲插槽上拍摄的方法。 3. 你应该分解你的代码:你在 computer 方法中做了九次完全相同的事情。

标签: c# wpf


【解决方案1】:

在大多数情况下,当您有一个在没有适当的暂停子句的情况下调用的递归方法时,就会发生 StackOverflowException。在您的情况下,罪魁祸首可能是 very 混乱的 computer() 方法,它在 几个 地方调用自己,因此很难从逻辑上推断可能导致无限的流程递归。但是扫描后,我想说核心原因在于您的randomSquare方法。

使用Random 类的正确方法是初始化一次,然后在同一个实例上调用Next()。这样您就知道它是从一个随机种子初始化的,然后所有后续调用都基于该种子。默认情况下,随机种子基于当前系统时钟。当您为每次调用初始化 Random 时,您实际上是根据系统时钟为每次调用创建一个新的随机种子,并且由于它是一个非常紧凑的循环,所有这些随机数将返回相同的数字 连续多次。这意味着您的computer 方法将连续获得几十/十/千个(每个调用computer,递归),直到系统时钟发生足够的变化。他们可能会连续获得几十/十/千个三。

这会很快耗尽你的堆栈,导致堆栈溢出。

尝试将rnd 更改为成员字段,在构造函数中将其实例化一次,然后在您的randomSquare 方法中调用rnd.Next

【讨论】:

  • @amaidie90 field 是为 class 定义的变量 - 在您的情况下为 MainWindow,而不是在该类的特定方法中。您在方法之外声明它,在构造函数中分配一个值,并且在该类的每个方法中都可以访问它。
  • 我按照你说的做了,帮了大忙!我在“MainWindow”类中声明并实例化了一次“rnd”,并在“randomSquare”方法中留下了“rnd.Next”。以前,它在游戏的许多不同点上到处乱扔错误。现在,它只在人类先走并且是第 9 步时抛出错误。有什么建议么?你帮了很多忙,谢谢!
  • 好吧,我们已经消除了 一些 逻辑递归错误,但不是全部。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多