System.Threading.Timer 不执行回调,但不抛出错误

System.Threading.Timer doesnt execute its callback, but doesnt throw an error

我计划用 dotnet 创建一个命令行程序,它使用菜单让用户决定他们想玩什么游戏(我已经制作但没有实现 tictactoe,我正在尝试创建一个糟糕的游戏蛇版)然后播放它们。我有三个独立的 类,一个用于菜单,一个用于 Snake,一个用于 Tictactoe(未实现,未显示)。

对于贪吃蛇,我尝试过使用System.Threading.Timer不断刷新棋盘状态。

菜单 Class:

using System;
using System.Threading;

namespace Boolean_Operators
{
    public class Menu
    {
        static Snake SnakeGame = new Snake();
        // var Tictactoe = new Tictactoe();

        static void Main(string[] args)
        {
            RunGame();
        }
        static void RunGame()
        {
            Timer refreshTimer = new Timer(SnakeGame.PrintBoard, null, 0, 1000);
            if(SnakeGame.invokeCount == SnakeGame.maxCount)
            {
                refreshTimer.Dispose();
            }
        }
    }
}

蛇Class:

using System;
using System.Threading;

namespace Boolean_Operators
{
    public class Snake
    {
        public int invokeCount = 0;
        public int maxCount = 20;
        string[,] board = new string[,]{
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",},
            {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ",}
        };
        

        public void PrintBoard(object state)
        {
            invokeCount++;
            for(int i = 0; i <= 10; i++)
            {
                Console.BackgroundColor = ConsoleColor.DarkGreen;
                Console.Write($"  {board[i, 0]}  |  {board[i, 1]}  |  {board[i, 2]}  |  {board[i, 3]}  |  {board[i, 4]}  |  {board[i, 5]}  |  {board[i, 6]}  |  {board[i, 7]}  |  {board[i, 8]}  |  {board[i, 9]}  ");
                Console.BackgroundColor = ConsoleColor.Black;
                Console.Write("\n");
                Console.BackgroundColor = ConsoleColor.DarkGreen;
                Console.Write("-----+-----+-----+-----+-----+-----+-----+-----+-----+-----");
                Console.BackgroundColor = ConsoleColor.Black;
                Console.Write("\n");
            }
            Console.BackgroundColor = ConsoleColor.DarkGreen;
            Console.Write($"  {board[9, 0]}  |  {board[9, 1]}  |  {board[9, 2]}  |  {board[9, 3]}  |  {board[9, 4]}  |  {board[9, 5]}  |  {board[9, 6]}  |  {board[9, 7]}  |  {board[9, 8]}  |  {board[9, 9]}  ");
            Console.BackgroundColor = ConsoleColor.Black;
            Console.Write("\n");
        }
    }
    
}

无论出于何种原因,所有代码似乎都在执行,但 PrintBoard 方法代码从未执行过,并且当 运行 程序没有任何反应时:

Console Output when running

我希望答案是我错过的非常明显的东西,因为我尝试了很多垃圾东西来试图绕过它。

RunGame 中,这些是步骤:

  1. 创建新计时器
  2. 0-N 个定时器回调(可能是 0 个)。
  3. 之后评估 if 语句,这将是错误的。
  4. 0-N 个定时器回调(可能是 0 个)。
  5. 退出程序

您的计时器永远不会有机会调用,或者即使有,也只会在程序退出前调用几次。

完成第 1 步后,您必须在 Main() 内等待。 Timer class documentation shows you a way to do that using AutoResetEvent. Another way you could do that is to do a SpinWait.SpinUntil 调用。您可以将代码更改为

static void RunGame()
{
    Timer refreshTimer = new Timer(SnakeGame.PrintBoard, null, 0, 1000);
    SpinWait.SpinUntil(() => SnakeGame.invokeCount == SnakeGame.maxCount);
    refreshTimer.Dispose();
}

这会阻止 Main(),直到满足条件。