为什么System.Threading.Timer会自行停止?

Tom*_*lis 17 .net c# service timer

在我使用System.Threading.TimerWindows服务项目之前,我正在做一个小型测试项目.它工作得非常好,但计时器会在一两分钟后自行停止.

测试项目的完整来源是:

using System;
using System.Windows.Forms;
using System.Threading;

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

        private void Form1_Load(object sender, EventArgs e) {
            TimerCallback timerDelegate = new TimerCallback(tick);
            System.Threading.Timer testTimer = new System.Threading.Timer(timerDelegate, null, 1000, 1000);
        }

        void tick(Object obj) {
            if (label1.InvokeRequired) {
                label1.Invoke(new MethodInvoker(() => tick(obj)));
            } else {
                label1.Text = DateTime.Now.ToString();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,目标是用当前时间更新标签.我注意到稍后更新停止了.为什么会这样?

Aar*_*ght 37

如果你在Windows窗体上需要一个计时器,那么就把它System.Windows.Forms.Timer放到表格上 - System.Threading.Timer除非你需要比55毫秒更好的分辨率,否则没有理由使用它.

计时器"停止"的原因是因为它被垃圾收集.您允许它超出Form1_Load方法的范围,因为您只将它声明为局部变量.为了使计时器"保持活动",它必须是表单类上的私有字段,以便GC知道它仍然需要.

换一种说法:

public partial class Form1 : Form
{
    private System.Threading.Timer testTimer;

    ...

    public void Form1_Load(object sender, EventArgs e)
    {
        TimerCallback timerDelegate = new TimerCallback(tick);
        testTimer = new System.Threading.Timer(timerDelegate, null, 1000, 1000);
    }
}
Run Code Online (Sandbox Code Playgroud)

但同样,在这种情况下,使用起来更简单System.Windows.Forms.Timer,这是工具箱中的一个实际组件,您可以将其放到表单上.


编辑 -正如现在的注释透露,如果这仅仅是一个测试应用程序,并在实际应用中是在Windows服务,您不能使用System.Windows.Forms.Timer了点.请记住不要让你System.Threading.Timer的范围超出范围.